Ticket #2025: pathfind.patch

File pathfind.patch, 148.2 KB (added by tuan kuranes, 11 years ago)
  • source/maths/Sqrt.h

     
    2222 * 64-bit integer square root.
    2323 * Returns r such that r^2 <= n < (r+1)^2, for the complete u64 range.
    2424 */
    25 u32 isqrt64(u64 n);
    2625
     26
     27// TODO: This should be equivalent to (u32)sqrt((double)n), and in practice
     28// that seems to be true for all input, so do we actually need this integer-only
     29// implementation? i.e. are there any platforms / compiler settings where
     30// sqrt(double) won't give the correct answer? and is sqrt(double) faster?
     31// TODO: read, decide and benchmark
     32// http://omeg.pl/blog/2012/03/performance-of-various-square-root-computing-algorithms/
     33// at least incredibly faster on win64 32bit build. (talking about 15% of cpu profile against 0.1% ...)
     34
     35//#define NATIVE_SQRT
     36#ifndef NATIVE_SQRT
     37static inline u32 isqrt64(const u64 n)
     38{
     39    u64 one = (u64)1 << 62; // highest power of four <= than the argument
     40    while (one > n)
     41        one >>= 2;
     42
     43    u64 op = n;
     44    u64 res = 0;
     45    while (one != 0)
     46    {
     47        if (op >= res + one)
     48        {
     49            op -= (res + one);
     50            res += (one << 1);
     51        }
     52        res >>= 1;
     53        one >>= 2;
     54    }
     55    return (u32)res;
     56}
     57#else
     58    #define isqrt64(n) ((u32)sqrt((double)(n)))
     59#endif
     60
    2761#endif // INCLUDED_MATH_SQRT
  • source/maths/Sqrt.cpp

     
    1818#include "precompiled.h"
    1919
    2020#include "Sqrt.h"
    21 
    22 // Based on http://freaknet.org/martin/tape/gos/misc/personal/msc/sqrt/sqrt.html
    23 u32 isqrt64(u64 n)
    24 {
    25     u64 op = n;
    26     u64 res = 0;
    27     u64 one = (u64)1 << 62; // highest power of four <= than the argument
    28 
    29     while (one > op)
    30         one >>= 2;
    31 
    32     while (one != 0)
    33     {
    34         if (op >= res + one)
    35         {
    36             op -= (res + one);
    37             res += (one << 1);
    38         }
    39         res >>= 1;
    40         one >>= 2;
    41     }
    42     return (u32)res;
    43 }
    44 
    45 // TODO: This should be equivalent to (u32)sqrt((double)n), and in practice
    46 // that seems to be true for all input, so do we actually need this integer-only
    47 // implementation? i.e. are there any platforms / compiler settings where
    48 // sqrt(double) won't give the correct answer? and is sqrt(double) faster?
  • source/maths/FixedVector2D.h

     
    9595    fixed Length() const
    9696    {
    9797        // Do intermediate calculations with 64-bit ints to avoid overflows
    98         i64 x = (i64)X.GetInternalValue();
    99         i64 y = (i64)Y.GetInternalValue();
    100         u64 xx = (u64)(x * x);
    101         u64 yy = (u64)(y * y);
    102         u64 d2 = xx + yy;
     98        const i64 x = (i64)X.GetInternalValue();
     99        const i64 y = (i64)Y.GetInternalValue();
     100        const u64 xx = (u64)(x * x);
     101        const u64 yy = (u64)(y * y);
     102        const u64 d2 = xx + yy;
    103103        CheckUnsignedAdditionOverflow(d2, xx, L"Overflow in CFixedVector2D::Length() part 1")
    104104
    105         u32 d = isqrt64(d2);
     105        const u32 d = isqrt64(d2);
    106106
    107107        CheckU32CastOverflow(d, i32, L"Overflow in CFixedVector2D::Length() part 2")
    108108        fixed r;
    109109        r.SetInternalValue((i32)d);
    110110        return r;
    111111    }
     112    /**
     113     * Returns the squared length of distance bewteen this vector and another
     114     * Will not overflow if the result can be represented as type 'fixed'.
     115     * faster than comparing two length (saving a squareroot operation)
     116     */
     117    fixed computeDistanceLengthSquared(const CFixedVector2D& src) const
     118    {       
     119        const i64 x = (i64)X.GetInternalValue() - (i64)src.X.GetInternalValue();
     120        const i64 y = (i64)Y.GetInternalValue() - (i64)src.Y.GetInternalValue();       
     121        const u64 d2 = (u64)(x * x) + (u64)(y * y);
     122        fixed r;
     123        r.SetInternalValue((i32)(d2 & 0x0000ffff));
     124        return r;
     125    }
     126   
     127    /**
     128     * Returns the squared length of distance bewteen this vector and another
     129     * Will not overflow if the result can be represented as type 'fixed'.
     130     */
     131    fixed computeDistanceLength(const CFixedVector2D& src) const
     132    {
     133        const i64 x = (i64)X.GetInternalValue() - (i64)src.X.GetInternalValue();
     134        const i64 y = (i64)Y.GetInternalValue() - (i64)src.Y.GetInternalValue();       
     135        const u64 xx = (u64)(x * x);
     136        const u64 yy = (u64)(y * y);
     137        const u64 d2 = xx + yy;
     138        CheckUnsignedAdditionOverflow(d2, xx, L"Overflow in CFixedVector2D::Length() part 1")
    112139
     140        const u32 d = isqrt64(d2);
     141
     142        CheckU32CastOverflow(d, i32, L"Overflow in CFixedVector2D::Length() part 2")
     143        fixed r;
     144        r.SetInternalValue((i32)d);
     145        return r;
     146    }
    113147    /**
    114148     * Returns -1, 0, +1 depending on whether length is less/equal/greater
    115149     * than the argument.
     
    188222            Y = Y.MulDiv(n, l);
    189223        }
    190224    }
     225    /**
     226     * Compute the dot product of this vector with another.
     227     */
     228    inline fixed SubFromAndDot(const fixed aX, const fixed aY, const CFixedVector2D& v) const
     229    {
     230        i64 x = (i64)(aX - X).GetInternalValue() * (i64)v.X.GetInternalValue();
     231        i64 y = (i64)(aY - Y).GetInternalValue() * (i64)v.Y.GetInternalValue();
     232        CheckSignedAdditionOverflow(i64, x, y, L"Overflow in CFixedVector2D::Dot() part 1", L"Underflow in CFixedVector2D::Dot() part 1")
     233        i64 sum = x + y;
     234        sum >>= fixed::fract_bits;
    191235
     236        CheckCastOverflow(sum, i32, L"Overflow in CFixedVector2D::Dot() part 2", L"Underflow in CFixedVector2D::Dot() part 2")
     237        fixed ret;
     238        ret.SetInternalValue((i32)sum);
     239        return ret;
     240    }
    192241    /**
    193242     * Compute the dot product of this vector with another.
    194243     */
    195     fixed Dot(const CFixedVector2D& v)
     244    inline fixed SubAndDot(const CFixedVector2D& b, const CFixedVector2D& v) const
    196245    {
     246        i64 x = (i64)(X - b.X).GetInternalValue() * (i64)v.X.GetInternalValue();
     247        i64 y = (i64)(Y - b.Y).GetInternalValue() * (i64)v.Y.GetInternalValue();
     248        CheckSignedAdditionOverflow(i64, x, y, L"Overflow in CFixedVector2D::Dot() part 1", L"Underflow in CFixedVector2D::Dot() part 1")
     249        i64 sum = x + y;
     250        sum >>= fixed::fract_bits;
     251
     252        CheckCastOverflow(sum, i32, L"Overflow in CFixedVector2D::Dot() part 2", L"Underflow in CFixedVector2D::Dot() part 2")
     253        fixed ret;
     254        ret.SetInternalValue((i32)sum);
     255        return ret;
     256    }
     257    /**
     258     * Compute the dot product of this vector with another.
     259     */
     260    inline fixed Dot(const CFixedVector2D& v) const
     261    {
    197262        i64 x = (i64)X.GetInternalValue() * (i64)v.X.GetInternalValue();
    198263        i64 y = (i64)Y.GetInternalValue() * (i64)v.Y.GetInternalValue();
    199264        CheckSignedAdditionOverflow(i64, x, y, L"Overflow in CFixedVector2D::Dot() part 1", L"Underflow in CFixedVector2D::Dot() part 1")
     
    206271        return ret;
    207272    }
    208273
    209     CFixedVector2D Perpendicular()
     274    CFixedVector2D Perpendicular() const
    210275    {
    211276        return CFixedVector2D(Y, -X);
    212277    }
     
    214279    /**
    215280     * Rotate the vector by the given angle (anticlockwise).
    216281     */
    217     CFixedVector2D Rotate(fixed angle)
     282    CFixedVector2D Rotate(fixed angle) const
    218283    {
    219284        fixed s, c;
    220285        sincos_approx(angle, s, c);
  • source/maths/Fixed.h

     
    107107class CFixed
    108108{
    109109private:
    110     T value;
    111110
    112111    explicit CFixed(T v) : value(v) { }
    113112
    114113public:
     114    T value;
    115115    enum { fract_bits = fract_bits_ };
    116116
    117117    CFixed() : value(0) { }
     
    191191    bool IsZero() const { return value == 0; }
    192192
    193193    /// Equality.
    194     bool operator==(CFixed n) const { return (value == n.value); }
     194    bool operator==(const CFixed& n) const { return (value == n.value); }
    195195
    196196    /// Inequality.
    197     bool operator!=(CFixed n) const { return (value != n.value); }
     197    bool operator!=(const CFixed& n) const { return (value != n.value); }
    198198
    199199    /// Numeric comparison.
    200     bool operator<=(CFixed n) const { return (value <= n.value); }
     200    bool operator<=(const CFixed& n) const { return (value <= n.value); }
    201201
    202202    /// Numeric comparison.
    203     bool operator<(CFixed n) const { return (value < n.value); }
     203    bool operator<(const CFixed& n) const { return (value < n.value); }
    204204
    205205    /// Numeric comparison.
    206     bool operator>=(CFixed n) const { return (value >= n.value); }
     206    bool operator>=(const CFixed& n) const { return (value >= n.value); }
    207207
    208208    /// Numeric comparison.
    209     bool operator>(CFixed n) const { return (value > n.value); }
     209    bool operator>(const CFixed& n) const { return (value > n.value); }
    210210
    211211    // Basic arithmetic:
    212212
    213213    /// Add a CFixed. Might overflow.
    214     CFixed operator+(CFixed n) const
     214    CFixed operator+(const CFixed& n) const
    215215    {
    216216        CheckSignedAdditionOverflow(T, value, n.value, L"Overflow in CFixed::operator+(CFixed n)", L"Underflow in CFixed::operator+(CFixed n)")
    217217        return CFixed(value + n.value);
    218218    }
    219219
    220220    /// Subtract a CFixed. Might overflow.
    221     CFixed operator-(CFixed n) const
     221    CFixed operator-(const CFixed& n) const
    222222    {
    223223        CheckSignedSubtractionOverflow(T, value, n.value, L"Overflow in CFixed::operator-(CFixed n)", L"Underflow in CFixed::operator-(CFixed n)")
    224224        return CFixed(value - n.value);
    225225    }
    226226
    227227    /// Add a CFixed. Might overflow.
    228     CFixed& operator+=(CFixed n) { *this = *this + n; return *this; }
     228    CFixed& operator+=(const CFixed& n) { *this = *this + n; return *this; }
    229229
    230230    /// Subtract a CFixed. Might overflow.
    231     CFixed& operator-=(CFixed n) { *this = *this - n; return *this; }
     231    CFixed& operator-=(const CFixed& n) { *this = *this - n; return *this; }
    232232
    233233    /// Negate a CFixed.
    234234    CFixed operator-() const
     
    238238    }
    239239
    240240    /// Divide by a CFixed. Must not have n.IsZero(). Might overflow.
    241     CFixed operator/(CFixed n) const
     241    CFixed operator/(const CFixed& n) const
    242242    {
    243243        i64 t = (i64)value << fract_bits;
    244244        i64 result = t / (i64)n.value;
     
    262262    }
    263263
    264264    /// Mod by a fixed. Must not have n == 0. Result has the same sign as n.
    265     CFixed operator%(CFixed n) const
     265    CFixed operator%(const CFixed& n) const
    266266    {
    267267        T t = value % n.value;
    268268        if (n.value > 0 && t < 0)
     
    279279     * Multiply by a CFixed. Likely to overflow if both numbers are large,
    280280     * so we use an ugly name instead of operator* to make it obvious.
    281281     */
    282     CFixed Multiply(CFixed n) const
     282    CFixed Multiply(const CFixed& n) const
    283283    {
    284284        i64 t = (i64)value * (i64)n.value;
    285285        t >>= fract_bits;
     
    299299    /**
    300300     * Compute this*m/d. Must not have d == 0. Won't overflow if the result can be represented as a CFixed.
    301301     */
    302     CFixed MulDiv(CFixed m, CFixed d) const
     302    CFixed MulDiv(const CFixed& m, const CFixed& d) const
    303303    {
    304304        i64 t = ((i64)value * (i64)m.value) / (i64)d.value;
    305305        CheckCastOverflow(t, T, L"Overflow in CFixed::Multiply(CFixed n)", L"Underflow in CFixed::Multiply(CFixed n)")
  • source/tools/atlas/GameInterface/Brushes.cpp

     
    5252        --max_j_inclusive;
    5353    }
    5454
    55     void ProcessTile(ssize_t i, ssize_t j)
     55    void ProcessTile(const ssize_t i, const ssize_t j)
    5656    {
    5757        ssize_t i0, j0;
    5858        m_Brush->GetBottomLeft(i0, j0);
  • source/renderer/TerrainOverlay.h

     
    123123     * @param i  <i>i</i> coordinate of tile being processed
    124124     * @param j  <i>j</i> coordinate of tile being processed
    125125     */
    126     virtual void ProcessTile(ssize_t i, ssize_t j) = 0;
     126    virtual void ProcessTile(const ssize_t i, const ssize_t j) = 0;
    127127
    128128    /**
    129129     * Draw a filled quad on top of the current tile.
  • source/simulation2/helpers/Geometry.h

     
    4747 * @return true if @p point is inside the square with rotated X axis unit vector @p u and rotated Z axis unit vector @p v,
    4848 * and half dimensions specified by @p halfSizes.
    4949 */
    50 bool PointIsInSquare(CFixedVector2D point, CFixedVector2D u, CFixedVector2D v, CFixedVector2D halfSize);
     50bool PointIsInSquare(const CFixedVector2D& point, const CFixedVector2D& u, const CFixedVector2D& v, const CFixedVector2D& halfSize);
    5151
    52 CFixedVector2D GetHalfBoundingBox(CFixedVector2D u, CFixedVector2D v, CFixedVector2D halfSize);
     52CFixedVector2D GetHalfBoundingBox(const CFixedVector2D& u, const CFixedVector2D& v, const CFixedVector2D& halfSize);
    5353
    54 fixed DistanceToSquare(CFixedVector2D point, CFixedVector2D u, CFixedVector2D v, CFixedVector2D halfSize);
     54fixed DistanceToSquare(const CFixedVector2D& point, const CFixedVector2D& u, const CFixedVector2D& v, const CFixedVector2D& halfSize);
    5555
    5656/**
    5757 * Given a circle of radius @p radius, and a chord of length @p chordLength on this circle, computes the central angle formed by
     
    7575 * @return point that is closest to @p point on the edge of the square specified by orientation unit vectors @p u and @p v and half
    7676 *  dimensions @p halfSize, relative to the center of the square
    7777 */
    78 CFixedVector2D NearestPointOnSquare(CFixedVector2D point, CFixedVector2D u, CFixedVector2D v, CFixedVector2D halfSize);
     78CFixedVector2D NearestPointOnSquare(const CFixedVector2D& point, const CFixedVector2D& u, const CFixedVector2D& v, const CFixedVector2D& halfSize);
    7979
    80 bool TestRaySquare(CFixedVector2D a, CFixedVector2D b, CFixedVector2D u, CFixedVector2D v, CFixedVector2D halfSize);
     80bool TestRaySquare(const CFixedVector2D&  a, const CFixedVector2D&  b, const CFixedVector2D& u, const CFixedVector2D& v, const CFixedVector2D& halfSize);
    8181
    82 bool TestRayAASquare(CFixedVector2D a, CFixedVector2D b, CFixedVector2D halfSize);
     82bool TestRayAASquare(const CFixedVector2D&  a, const CFixedVector2D& b, const CFixedVector2D& halfSize);
    8383
    8484bool TestSquareSquare(
    85         CFixedVector2D c0, CFixedVector2D u0, CFixedVector2D v0, CFixedVector2D halfSize0,
    86         CFixedVector2D c1, CFixedVector2D u1, CFixedVector2D v1, CFixedVector2D halfSize1);
     85        const CFixedVector2D&  c0, const CFixedVector2D&  u0, const CFixedVector2D&   v0, const CFixedVector2D&  halfSize0,
     86        const CFixedVector2D&   c1, const CFixedVector2D&   u1, const CFixedVector2D&   v1, const CFixedVector2D&  halfSize1);
    8787
    8888} // namespace
    89 
    9089#endif // INCLUDED_HELPER_GEOMETRY
  • source/simulation2/helpers/Spatial.h

     
    7272        return !(*this == rhs);
    7373    }
    7474
    75     void Reset(entity_pos_t maxX, entity_pos_t maxZ, entity_pos_t divisionSize)
     75    void Reset(const entity_pos_t maxX, const entity_pos_t maxZ, const entity_pos_t divisionSize)
    7676    {
    7777        m_DivisionSize = divisionSize;
    7878        m_DivisionsW = (maxX / m_DivisionSize).ToInt_RoundToInfinity();
     
    8585     * Add an item with the given 'to' size.
    8686     * The item must not already be present.
    8787     */
    88     void Add(T item, CFixedVector2D toMin, CFixedVector2D toMax)
     88    void Add(const T& item, const CFixedVector2D& toMin,  const CFixedVector2D& toMax)
    8989    {
    9090        ENSURE(toMin.X <= toMax.X && toMin.Y <= toMax.Y);
    9191
    92         u32 i0 = GetI0(toMin.X);
    93         u32 j0 = GetJ0(toMin.Y);
    94         u32 i1 = GetI1(toMax.X);
    95         u32 j1 = GetJ1(toMax.Y);
     92        const u32 i0 = GetI0(toMin.X);
     93        const u32 j0 = GetJ0(toMin.Y);
     94        const u32 i1 = GetI1(toMax.X);
     95        const u32 j1 = GetJ1(toMax.Y);
    9696        for (u32 j = j0; j <= j1; ++j)
    9797        {
    9898            for (u32 i = i0; i <= i1; ++i)
     
    108108     * The item should already be present.
    109109     * The size must match the size that was last used when adding the item.
    110110     */
    111     void Remove(T item, CFixedVector2D fromMin, CFixedVector2D fromMax)
     111    void Remove(const T& item,  const CFixedVector2D& fromMin,  const CFixedVector2D& fromMax)
    112112    {
    113113        ENSURE(fromMin.X <= fromMax.X && fromMin.Y <= fromMax.Y);
    114114
     
    139139    /**
    140140     * Equivalent to Remove() then Add(), but potentially faster.
    141141     */
    142     void Move(T item, CFixedVector2D fromMin, CFixedVector2D fromMax, CFixedVector2D toMin, CFixedVector2D toMax)
     142    void Move(const T& item,  const CFixedVector2D& fromMin,  const CFixedVector2D& fromMax,  const CFixedVector2D& toMin,  const CFixedVector2D& toMax)
    143143    {
    144144        // Skip the work if we're staying in the same divisions
    145145        if (GetIndex0(fromMin) == GetIndex0(toMin) && GetIndex1(fromMax) == GetIndex1(toMax))
     
    153153     * Convenience function for Add() of individual points.
    154154     * (Note that points on a boundary may occupy multiple divisions.)
    155155     */
    156     void Add(T item, CFixedVector2D to)
     156    void Add(const T& item,  const CFixedVector2D& to)
    157157    {
    158158        Add(item, to, to);
    159159    }
     
    161161    /**
    162162     * Convenience function for Remove() of individual points.
    163163     */
    164     void Remove(T item, CFixedVector2D from)
     164    void Remove(const T& item, const CFixedVector2D& from)
    165165    {
    166166        Remove(item, from, from);
    167167    }
     
    169169    /**
    170170     * Convenience function for Move() of individual points.
    171171     */
    172     void Move(T item, CFixedVector2D from, CFixedVector2D to)
     172    void Move(const T& item,  const CFixedVector2D& from,  const CFixedVector2D& to)
    173173    {
    174174        Move(item, from, from, to, to);
    175175    }
     
    178178     * Returns a sorted list of unique items that includes all items
    179179     * within the given axis-aligned square range.
    180180     */
    181     std::vector<T> GetInRange(CFixedVector2D posMin, CFixedVector2D posMax)
     181    void GetInRange(const CFixedVector2D& posMin, const CFixedVector2D& posMax, std::vector<T> &ret) const
    182182    {
    183         std::vector<T> ret;
    184 
    185183        ENSURE(posMin.X <= posMax.X && posMin.Y <= posMax.Y);
    186184
    187         u32 i0 = GetI0(posMin.X);
    188         u32 j0 = GetJ0(posMin.Y);
    189         u32 i1 = GetI1(posMax.X);
    190         u32 j1 = GetJ1(posMax.Y);
    191         for (u32 j = j0; j <= j1; ++j)
     185        const u32 i0 = GetI0(posMin.X);
     186        const u32 j0 = GetJ0(posMin.Y);
     187        const u32 i1 = GetI1(posMax.X);
     188        const u32 j1 = GetJ1(posMax.Y);
     189
     190        ret.reserve((i1 - i0)*(j1 - j0)*4);
     191        for (u32 j = j0; j <= j1; j++)
    192192        {
    193             for (u32 i = i0; i <= i1; ++i)
     193            for (u32 i = i0; i <= i1; i++)
    194194            {
    195                 std::vector<T>& div = m_Divisions.at(i + j*m_DivisionsW);
     195                const std::vector<T>& div = m_Divisions.at(i + j*m_DivisionsW);
    196196                ret.insert(ret.end(), div.begin(), div.end());
     197
    197198            }
    198199        }
    199200
     
    201202        std::sort(ret.begin(), ret.end());
    202203        ret.erase(std::unique(ret.begin(), ret.end()), ret.end());
    203204
    204         return ret;
    205205    }
    206206
    207207    /**
    208208     * Returns a sorted list of unique items that includes all items
    209209     * within the given circular distance of the given point.
    210210     */
    211     std::vector<T> GetNear(CFixedVector2D pos, entity_pos_t range)
     211    void GetNear(const CFixedVector2D& pos, const entity_pos_t range, std::vector<T> &ents) const
    212212    {
    213213        // TODO: be cleverer and return a circular pattern of divisions,
    214214        // not this square over-approximation
    215215
    216         return GetInRange(pos - CFixedVector2D(range, range), pos + CFixedVector2D(range, range));
     216        return GetInRange(pos - CFixedVector2D(range, range), pos + CFixedVector2D(range, range), ents);
    217217    }
    218218
    219219private:
     
    221221    // (avoiding out-of-bounds accesses, and rounding correctly so that
    222222    // points precisely between divisions are counted in both):
    223223
    224     u32 GetI0(entity_pos_t x)
     224    u32 GetI0(const entity_pos_t x) const
    225225    {
    226226        return Clamp((x / m_DivisionSize).ToInt_RoundToInfinity()-1, 0, (int)m_DivisionsW-1);
    227227    }
    228228
    229     u32 GetJ0(entity_pos_t z)
     229    u32 GetJ0(const entity_pos_t z) const
    230230    {
    231231        return Clamp((z / m_DivisionSize).ToInt_RoundToInfinity()-1, 0, (int)m_DivisionsH-1);
    232232    }
    233233
    234     u32 GetI1(entity_pos_t x)
     234    u32 GetI1(const entity_pos_t x) const
    235235    {
    236236        return Clamp((x / m_DivisionSize).ToInt_RoundToNegInfinity(), 0, (int)m_DivisionsW-1);
    237237    }
    238238
    239     u32 GetJ1(entity_pos_t z)
     239    u32 GetJ1(const entity_pos_t z) const
    240240    {
    241241        return Clamp((z / m_DivisionSize).ToInt_RoundToNegInfinity(), 0, (int)m_DivisionsH-1);
    242242    }
    243243
    244     u32 GetIndex0(CFixedVector2D pos)
     244    u32 GetIndex0(const CFixedVector2D& pos) const
    245245    {
    246246        return GetI0(pos.X) + GetJ0(pos.Y)*m_DivisionsW;
    247247    }
    248248
    249     u32 GetIndex1(CFixedVector2D pos)
     249    u32 GetIndex1(const CFixedVector2D& pos) const
    250250    {
    251251        return GetI1(pos.X) + GetJ1(pos.Y)*m_DivisionsW;
    252252    }
  • source/simulation2/helpers/Grid.h

     
    8080            memset(m_Data, 0, m_W*m_H*sizeof(T));
    8181    }
    8282
    83     void set(int i, int j, const T& value)
     83    void set(const int i, const int j, const T& value)
    8484    {
    8585#if GRID_BOUNDS_DEBUG
    8686        ENSURE(0 <= i && i < m_W && 0 <= j && j < m_H);
    8787#endif
    8888        m_Data[j*m_W + i] = value;
    8989    }
     90   
     91    void add(const int i, const int j, T val)
     92    {
     93#if GRID_BOUNDS_DEBUG
     94        ENSURE(0 <= i && i < m_W && 0 <= j && j < m_H);
     95#endif
     96        m_Data[j*m_W + i] += val;
     97    }
     98    void getPtr(const int i, const int j)
     99    {
     100#if GRID_BOUNDS_DEBUG
     101        ENSURE(0 <= i && i < m_W && 0 <= j && j < m_H);
     102#endif
     103        return m_Data[j*m_W + i];
     104    }
    90105
    91     T& get(int i, int j) const
     106    T& get(const int i, const int j) const
    92107    {
    93108#if GRID_BOUNDS_DEBUG
    94109        ENSURE(0 <= i && i < m_W && 0 <= j && j < m_H);
     
    113128
    114129    enum { BucketBits = 4, BucketSize = 1 << BucketBits };
    115130
    116     T* GetBucket(int i, int j)
     131    T* GetBucket(const int i, const int j)
    117132    {
    118         size_t b = (j >> BucketBits) * m_BW + (i >> BucketBits);
     133        const size_t b = (j >> BucketBits) * m_BW + (i >> BucketBits);
    119134        if (!m_Data[b])
    120135        {
    121             m_Data[b] = new T[BucketSize*BucketSize];
     136            if (m_Reserve.empty())
     137            {               
     138                m_Data[b] = new T[BucketSize*BucketSize];
     139            }
     140            else
     141            {
     142                m_Data[b] = m_Reserve.back();
     143                m_Reserve.pop_back();
     144            }
    122145            memset(m_Data[b], 0, BucketSize*BucketSize*sizeof(T));
    123146        }
    124147        return m_Data[b];
     
    134157
    135158        m_Data = new T*[m_BW*m_BH];
    136159        memset(m_Data, 0, m_BW*m_BH*sizeof(T*));
     160
    137161    }
    138162
    139163    ~SparseGrid()
    140     {
    141         reset();
     164    {       
     165        for (size_t i = 0; i < (size_t)(m_BW*m_BH); ++i)
     166            delete[] m_Data[i];
    142167        delete[] m_Data;
    143168    }
    144169
    145170    void reset()
    146     {
     171    {       
    147172        for (size_t i = 0; i < (size_t)(m_BW*m_BH); ++i)
    148             delete[] m_Data[i];
     173        {           
     174            if (m_Data[i])
     175            {
     176                m_Reserve.push_back(m_Data[i]);
     177            }
     178        }
    149179
    150180        memset(m_Data, 0, m_BW*m_BH*sizeof(T*));
    151181    }
    152182
    153     void set(int i, int j, const T& value)
     183    void set(const int i, const int j, const T& value)
    154184    {
    155185#if GRID_BOUNDS_DEBUG
    156186        ENSURE(0 <= i && i < m_W && 0 <= j && j < m_H);
     
    158188        GetBucket(i, j)[(j % BucketSize)*BucketSize + (i % BucketSize)] = value;
    159189    }
    160190
    161     T& get(int i, int j)
     191    T& get(const int i, const int j)
    162192    {
    163193#if GRID_BOUNDS_DEBUG
    164194        ENSURE(0 <= i && i < m_W && 0 <= j && j < m_H);
     
    169199    u16 m_W, m_H;
    170200    u16 m_BW, m_BH;
    171201    T** m_Data;
     202    std::deque < T* > m_Reserve;
    172203
    173204    size_t m_DirtyID; // if this is < the id maintained by ICmpObstructionManager then it needs to be updated
    174205};
  • source/simulation2/helpers/Geometry.cpp

     
    2525
    2626// TODO: all of these things could be optimised quite easily
    2727
    28 bool Geometry::PointIsInSquare(CFixedVector2D point, CFixedVector2D u, CFixedVector2D v, CFixedVector2D halfSize)
     28bool Geometry::PointIsInSquare(const CFixedVector2D& point, const CFixedVector2D&  u, const CFixedVector2D&  v, const CFixedVector2D& halfSize)
    2929{
    30     fixed du = point.Dot(u);
     30    const fixed du = point.Dot(u);
    3131    if (-halfSize.X <= du && du <= halfSize.X)
    3232    {
    33         fixed dv = point.Dot(v);
     33        const fixed dv = point.Dot(v);
    3434        if (-halfSize.Y <= dv && dv <= halfSize.Y)
    3535            return true;
    3636    }
    3737    return false;
    3838}
    3939
    40 CFixedVector2D Geometry::GetHalfBoundingBox(CFixedVector2D u, CFixedVector2D v, CFixedVector2D halfSize)
     40CFixedVector2D Geometry::GetHalfBoundingBox(const CFixedVector2D&  u, const CFixedVector2D&  v, const CFixedVector2D& halfSize)
    4141{
    4242    return CFixedVector2D(
    4343        u.X.Multiply(halfSize.X).Absolute() + v.X.Multiply(halfSize.Y).Absolute(),
     
    5050    return acosf(1.f - SQR(chordLength)/(2.f*SQR(radius))); // cfr. law of cosines
    5151}
    5252
    53 fixed Geometry::DistanceToSquare(CFixedVector2D point, CFixedVector2D u, CFixedVector2D v, CFixedVector2D halfSize)
     53fixed Geometry::DistanceToSquare(const CFixedVector2D& point, const CFixedVector2D&  u, const CFixedVector2D&  v, const CFixedVector2D& halfSize)
    5454{
    5555    /*
    5656     * Relative to its own coordinate system, we have a square like:
     
    7979     */
    8080
    8181    // du, dv are the location of the point in the square's coordinate system
    82     fixed du = point.Dot(u);
    83     fixed dv = point.Dot(v);
     82    const fixed du = point.Dot(u);
     83    const fixed dv = point.Dot(v);
    8484
    85     fixed hw = halfSize.X;
    86     fixed hh = halfSize.Y;
     85    const fixed hw = halfSize.X;
     86    const fixed hh = halfSize.Y;
    8787
    8888    // TODO: I haven't actually tested this
    8989
     
    116116    }
    117117}
    118118
    119 CFixedVector2D Geometry::NearestPointOnSquare(CFixedVector2D point, CFixedVector2D u, CFixedVector2D v, CFixedVector2D halfSize)
     119CFixedVector2D Geometry::NearestPointOnSquare(const CFixedVector2D&   point, const CFixedVector2D&   u, const CFixedVector2D&   v, const CFixedVector2D&  halfSize)
    120120{
    121121    /*
    122122     * Relative to its own coordinate system, we have a square like:
     
    144144     */
    145145
    146146    // du, dv are the location of the point in the square's coordinate system
    147     fixed du = point.Dot(u);
    148     fixed dv = point.Dot(v);
     147    const fixed du = point.Dot(u);
     148    const fixed dv = point.Dot(v);
    149149
    150     fixed hw = halfSize.X;
    151     fixed hh = halfSize.Y;
     150    const fixed hw = halfSize.X;
     151    const fixed hh = halfSize.Y;
    152152
    153153    if (-hw < du && du < hw) // regions B, G; or regions D, E inside the square
    154154    {
     
    190190    }
    191191}
    192192
    193 bool Geometry::TestRaySquare(CFixedVector2D a, CFixedVector2D b, CFixedVector2D u, CFixedVector2D v, CFixedVector2D halfSize)
     193bool Geometry::TestRaySquare(const CFixedVector2D&   a, const CFixedVector2D&   b, const CFixedVector2D&   u, const CFixedVector2D&   v, const CFixedVector2D&  halfSize)
    194194{
    195195    /*
    196196     * We only consider collisions to be when the ray goes from outside to inside the shape (and possibly out again).
     
    205205     * (Points on the edge are considered 'inside'.)
    206206     */
    207207
    208     fixed hw = halfSize.X;
    209     fixed hh = halfSize.Y;
     208    const fixed hw = halfSize.X;
     209    const fixed hh = halfSize.Y;
    210210
    211     fixed au = a.Dot(u);
    212     fixed av = a.Dot(v);
     211    const fixed au = a.Dot(u);
     212    const fixed av = a.Dot(v);
    213213
    214214    if (-hw <= au && au <= hw && -hh <= av && av <= hh)
    215215        return false; // a is inside
    216216
    217     fixed bu = b.Dot(u);
    218     fixed bv = b.Dot(v);
     217    const fixed bu = b.Dot(u);
     218    const fixed bv = b.Dot(v);
    219219
    220220    if (-hw <= bu && bu <= hw && -hh <= bv && bv <= hh) // TODO: isn't this subsumed by the next checks?
    221221        return true; // a is outside, b is inside
     
    223223    if ((au < -hw && bu < -hw) || (au > hw && bu > hw) || (av < -hh && bv < -hh) || (av > hh && bv > hh))
    224224        return false; // ab is entirely above/below/side the square
    225225
    226     CFixedVector2D abp = (b - a).Perpendicular();
    227     fixed s0 = abp.Dot((u.Multiply(hw) + v.Multiply(hh)) - a);
    228     fixed s1 = abp.Dot((u.Multiply(hw) - v.Multiply(hh)) - a);
    229     fixed s2 = abp.Dot((-u.Multiply(hw) - v.Multiply(hh)) - a);
    230     fixed s3 = abp.Dot((-u.Multiply(hw) + v.Multiply(hh)) - a);
     226    const CFixedVector2D abp ((b - a).Perpendicular());
     227    const fixed s0 = abp.Dot((u.Multiply(hw) + v.Multiply(hh)) - a);
     228    const fixed s1 = abp.Dot((u.Multiply(hw) - v.Multiply(hh)) - a);
     229    const fixed s2 = abp.Dot((-u.Multiply(hw) - v.Multiply(hh)) - a);
     230    const fixed s3 = abp.Dot((-u.Multiply(hw) + v.Multiply(hh)) - a);
    231231    if (s0.IsZero() || s1.IsZero() || s2.IsZero() || s3.IsZero())
    232232        return true; // ray intersects the corner
    233233
    234     bool sign = (s0 < fixed::Zero());
     234    const bool sign = (s0 < fixed::Zero());
    235235    if ((s1 < fixed::Zero()) != sign || (s2 < fixed::Zero()) != sign || (s3 < fixed::Zero()) != sign)
    236236        return true; // ray cuts through the square
    237237
    238238    return false;
    239239}
    240240
    241 bool Geometry::TestRayAASquare(CFixedVector2D a, CFixedVector2D b, CFixedVector2D halfSize)
     241bool Geometry::TestRayAASquare(const CFixedVector2D&   a, const CFixedVector2D&   b, const CFixedVector2D&  halfSize)
    242242{
    243243    // Exactly like TestRaySquare with u=(1,0), v=(0,1)
    244244
    245245    // Assume the compiler is clever enough to inline and simplify all this
    246246    // (TODO: stop assuming that)
    247     CFixedVector2D u (fixed::FromInt(1), fixed::Zero());
    248     CFixedVector2D v (fixed::Zero(), fixed::FromInt(1));
     247    const CFixedVector2D u (fixed::FromInt(1), fixed::Zero());
     248    const CFixedVector2D v (fixed::Zero(), fixed::FromInt(1));
    249249
    250     fixed hw = halfSize.X;
    251     fixed hh = halfSize.Y;
     250    const fixed hw = halfSize.X;
     251    const fixed hh = halfSize.Y;
    252252
    253     fixed au = a.Dot(u);
    254     fixed av = a.Dot(v);
     253    const fixed au = a.Dot(u);
     254    const fixed av = a.Dot(v);
    255255
    256256    if (-hw <= au && au <= hw && -hh <= av && av <= hh)
    257257        return false; // a is inside
    258258
    259     fixed bu = b.Dot(u);
    260     fixed bv = b.Dot(v);
     259    const fixed bu = b.Dot(u);
     260    const fixed bv = b.Dot(v);
    261261
    262262    if (-hw <= bu && bu <= hw && -hh <= bv && bv <= hh) // TODO: isn't this subsumed by the next checks?
    263263        return true; // a is outside, b is inside
     
    265265    if ((au < -hw && bu < -hw) || (au > hw && bu > hw) || (av < -hh && bv < -hh) || (av > hh && bv > hh))
    266266        return false; // ab is entirely above/below/side the square
    267267
    268     CFixedVector2D abp = (b - a).Perpendicular();
    269     fixed s0 = abp.Dot((u.Multiply(hw) + v.Multiply(hh)) - a);
    270     fixed s1 = abp.Dot((u.Multiply(hw) - v.Multiply(hh)) - a);
    271     fixed s2 = abp.Dot((-u.Multiply(hw) - v.Multiply(hh)) - a);
    272     fixed s3 = abp.Dot((-u.Multiply(hw) + v.Multiply(hh)) - a);
     268    const CFixedVector2D abp ((b - a).Perpendicular());
     269    const fixed s0 = abp.Dot((u.Multiply(hw) + v.Multiply(hh)) - a);
     270    const fixed s1 = abp.Dot((u.Multiply(hw) - v.Multiply(hh)) - a);
     271    const fixed s2 = abp.Dot((-u.Multiply(hw) - v.Multiply(hh)) - a);
     272    const fixed s3 = abp.Dot((-u.Multiply(hw) + v.Multiply(hh)) - a);
    273273    if (s0.IsZero() || s1.IsZero() || s2.IsZero() || s3.IsZero())
    274274        return true; // ray intersects the corner
    275275
    276     bool sign = (s0 < fixed::Zero());
     276    const bool sign = (s0 < fixed::Zero());
    277277    if ((s1 < fixed::Zero()) != sign || (s2 < fixed::Zero()) != sign || (s3 < fixed::Zero()) != sign)
    278278        return true; // ray cuts through the square
    279279
     
    284284 * Separating axis test; returns true if the square defined by u/v/halfSize at the origin
    285285 * is not entirely on the clockwise side of a line in direction 'axis' passing through 'a'
    286286 */
    287 static bool SquareSAT(CFixedVector2D a, CFixedVector2D axis, CFixedVector2D u, CFixedVector2D v, CFixedVector2D halfSize)
     287static bool SquareSAT(const CFixedVector2D&   a, const CFixedVector2D&   axis, const CFixedVector2D&   u, const CFixedVector2D&   v, const CFixedVector2D&  halfSize)
    288288{
    289     fixed hw = halfSize.X;
    290     fixed hh = halfSize.Y;
     289    const fixed hw = halfSize.X;
     290    const fixed hh = halfSize.Y;
    291291
    292     CFixedVector2D p = axis.Perpendicular();
     292    const CFixedVector2D p (axis.Perpendicular());
    293293    if (p.Dot((u.Multiply(hw) + v.Multiply(hh)) - a) <= fixed::Zero())
    294294        return true;
    295295    if (p.Dot((u.Multiply(hw) - v.Multiply(hh)) - a) <= fixed::Zero())
     
    303303}
    304304
    305305bool Geometry::TestSquareSquare(
    306         CFixedVector2D c0, CFixedVector2D u0, CFixedVector2D v0, CFixedVector2D halfSize0,
    307         CFixedVector2D c1, CFixedVector2D u1, CFixedVector2D v1, CFixedVector2D halfSize1)
     306        const CFixedVector2D&   c0, const CFixedVector2D&   u0, const CFixedVector2D&   v0, const CFixedVector2D&  halfSize0,
     307        const CFixedVector2D&   c1, const CFixedVector2D&   u1, const CFixedVector2D&   v1, const CFixedVector2D&  halfSize1)
    308308{
    309309    // TODO: need to test this carefully
    310310
    311     CFixedVector2D corner0a = c0 + u0.Multiply(halfSize0.X) + v0.Multiply(halfSize0.Y);
    312     CFixedVector2D corner0b = c0 - u0.Multiply(halfSize0.X) - v0.Multiply(halfSize0.Y);
    313     CFixedVector2D corner1a = c1 + u1.Multiply(halfSize1.X) + v1.Multiply(halfSize1.Y);
    314     CFixedVector2D corner1b = c1 - u1.Multiply(halfSize1.X) - v1.Multiply(halfSize1.Y);
     311    const CFixedVector2D corner0a ( c0 + u0.Multiply(halfSize0.X) + v0.Multiply(halfSize0.Y));
     312    const CFixedVector2D corner0b ( c0 - u0.Multiply(halfSize0.X) - v0.Multiply(halfSize0.Y));
     313    const CFixedVector2D corner1a ( c1 + u1.Multiply(halfSize1.X) + v1.Multiply(halfSize1.Y));
     314    const CFixedVector2D corner1b ( c1 - u1.Multiply(halfSize1.X) - v1.Multiply(halfSize1.Y));
    315315
    316316    // Do a SAT test for each square vs each edge of the other square
    317317    if (!SquareSAT(corner0a - c1, -u0, u1, v1, halfSize1))
  • source/simulation2/serialization/SerializeTemplates.h

     
    8686        }
    8787    }
    8888};
    89 
    9089// We have to order the map before serializing to make things consistent
    9190template<typename KS, typename VS>
    9291struct SerializeUnorderedMap
  • source/simulation2/system/InterfaceScripted.h

     
    6161        2, \
    6262        JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT },
    6363
     64
    6465#define DEFINE_INTERFACE_METHOD_3(scriptname, rettype, classname, methodname, arg1, arg2, arg3) \
    6566    { scriptname, \
    6667        ScriptInterface::callMethod<rettype, arg1, arg2, arg3, &class_##classname, classname, &classname::methodname>, \
     
    8586        6, \
    8687        JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT },
    8788
     89
    8890#endif // INCLUDED_INTERFACE_SCRIPTED
  • source/simulation2/components/ICmpPathfinder.h

     
    101101     * The waypoints correspond to the centers of horizontally/vertically adjacent tiles
    102102     * along the path.
    103103     */
    104     virtual void ComputePath(entity_pos_t x0, entity_pos_t z0, const Goal& goal, pass_class_t passClass, cost_class_t costClass, Path& ret) = 0;
     104    virtual void ComputePath(const entity_pos_t x0, const entity_pos_t z0, const Goal& goal, const pass_class_t passClass, const cost_class_t costClass, Path& ret) = 0;
    105105
    106106    /**
    107107     * Asynchronous version of ComputePath.
     
    109109     * Returns a unique non-zero number, which will match the 'ticket' in the result,
    110110     * so callers can recognise each individual request they make.
    111111     */
    112     virtual u32 ComputePathAsync(entity_pos_t x0, entity_pos_t z0, const Goal& goal, pass_class_t passClass, cost_class_t costClass, entity_id_t notify) = 0;
     112    virtual u32 ComputePathAsync(const entity_pos_t x0, const entity_pos_t z0, const Goal& goal, const pass_class_t passClass, const cost_class_t costClass, const entity_id_t notify) = 0;
    113113
    114114    /**
    115115     * If the debug overlay is enabled, render the path that will computed by ComputePath.
    116116     */
    117     virtual void SetDebugPath(entity_pos_t x0, entity_pos_t z0, const Goal& goal, pass_class_t passClass, cost_class_t costClass) = 0;
     117    virtual void SetDebugPath(const entity_pos_t x0, const entity_pos_t z0, const Goal& goal, const pass_class_t passClass, const cost_class_t costClass) = 0;
    118118
    119119    /**
    120120     * Compute a precise path from the given point to the goal, and return the set of waypoints.
     
    122122     * a unit of radius 'r' will be able to follow the path with no collisions.
    123123     * The path is restricted to a box of radius 'range' from the starting point.
    124124     */
    125     virtual void ComputeShortPath(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t r, entity_pos_t range, const Goal& goal, pass_class_t passClass, Path& ret) = 0;
     125    virtual void ComputeShortPath(const IObstructionTestFilter& filter, const entity_pos_t x0, const entity_pos_t z0, const entity_pos_t r, const entity_pos_t range, const Goal& goal, const pass_class_t passClass, Path& ret) = 0;
    126126
    127127    /**
    128128     * Asynchronous version of ComputeShortPath (using ControlGroupObstructionFilter).
     
    130130     * Returns a unique non-zero number, which will match the 'ticket' in the result,
    131131     * so callers can recognise each individual request they make.
    132132     */
    133     virtual u32 ComputeShortPathAsync(entity_pos_t x0, entity_pos_t z0, entity_pos_t r, entity_pos_t range, const Goal& goal, pass_class_t passClass, bool avoidMovingUnits, entity_id_t group, entity_id_t notify) = 0;
     133    virtual u32 ComputeShortPathAsync(const entity_pos_t x0, const entity_pos_t z0, const entity_pos_t r, const entity_pos_t range, const Goal& goal, const pass_class_t passClass, const bool avoidMovingUnits, const entity_id_t controller, const entity_id_t notify) = 0;
    134134
    135135    /**
    136136     * Find the speed factor (typically around 1.0) for a unit of the given cost class
    137137     * at the given position.
    138138     */
    139     virtual fixed GetMovementSpeed(entity_pos_t x0, entity_pos_t z0, cost_class_t costClass) = 0;
     139    virtual fixed GetMovementSpeed( const entity_pos_t x0, const entity_pos_t z0,  const cost_class_t costClass) = 0;
    140140
    141141    /**
    142142     * Returns the coordinates of the point on the goal that is closest to pos in a straight line.
    143143     */
    144     virtual CFixedVector2D GetNearestPointOnGoal(CFixedVector2D pos, const Goal& goal) = 0;
     144    virtual CFixedVector2D GetNearestPointOnGoal(const CFixedVector2D& pos, const Goal& goal) const = 0;
    145145
    146146    /**
    147147     * Check whether the given movement line is valid and doesn't hit any obstructions
  • source/simulation2/components/ICmpRangeManager.h

     
    196196        /**
    197197         * Returns whether the given vertex is visible (i.e. is within a unit's LOS).
    198198         */
    199         inline bool IsVisible(ssize_t i, ssize_t j)
     199        inline bool IsVisible(const ssize_t i, const ssize_t j) const
    200200        {
    201201            if (!(i >= 0 && j >= 0 && i < m_VerticesPerSide && j < m_VerticesPerSide))
    202202                return false;
     
    211211        /**
    212212         * Returns whether the given vertex is explored (i.e. was (or still is) within a unit's LOS).
    213213         */
    214         inline bool IsExplored(ssize_t i, ssize_t j)
     214        inline bool IsExplored(const ssize_t i, const ssize_t j) const
    215215        {
    216216            if (!(i >= 0 && j >= 0 && i < m_VerticesPerSide && j < m_VerticesPerSide))
    217217                return false;
     
    227227         * Returns whether the given vertex is visible (i.e. is within a unit's LOS).
    228228         * i and j must be in the range [0, verticesPerSide), else behaviour is undefined.
    229229         */
    230         inline bool IsVisible_UncheckedRange(ssize_t i, ssize_t j)
     230        inline bool IsVisible_UncheckedRange(const ssize_t i, const ssize_t j) const
    231231        {
    232232#ifndef NDEBUG
    233233            ENSURE(i >= 0 && j >= 0 && i < m_VerticesPerSide && j < m_VerticesPerSide);
     
    243243         * Returns whether the given vertex is explored (i.e. was (or still is) within a unit's LOS).
    244244         * i and j must be in the range [0, verticesPerSide), else behaviour is undefined.
    245245         */
    246         inline bool IsExplored_UncheckedRange(ssize_t i, ssize_t j)
     246        inline bool IsExplored_UncheckedRange(const ssize_t i, const ssize_t j) const
    247247        {
    248248#ifndef NDEBUG
    249249            ENSURE(i >= 0 && j >= 0 && i < m_VerticesPerSide && j < m_VerticesPerSide);
     
    275275     * TODO: This is a hack to allow preview entities in FoW to return fogged instead of hidden,
    276276     *  see http://trac.wildfiregames.com/ticket/958
    277277     */
    278     virtual ELosVisibility GetLosVisibility(entity_id_t ent, player_id_t player, bool forceRetainInFog = false) = 0;
     278    virtual ELosVisibility GetLosVisibility(const entity_id_t ent, const player_id_t player, const bool forceRetainInFog = false) = 0;
    279279
    280280    /**
    281281     * GetLosVisibility wrapped for script calls.
     
    287287     * Set whether the whole map should be made visible to the given player.
    288288     * If player is -1, the map will be made visible to all players.
    289289     */
    290     virtual void SetLosRevealAll(player_id_t player, bool enabled) = 0;
     290    virtual void SetLosRevealAll(const player_id_t player, const bool enabled) = 0;
    291291
    292292    /**
    293293     * Returns whether the whole map has been made visible to the given player.
    294294     */
    295     virtual bool GetLosRevealAll(player_id_t player) = 0;
     295    virtual bool GetLosRevealAll(const player_id_t player) = 0;
    296296
    297297    /**
    298298     * Set the LOS to be restricted to a circular map.
     
    312312    /**
    313313     * Returns shared LOS mask for player.
    314314     */
    315     virtual u32 GetSharedLosMask(player_id_t player) = 0;
     315    virtual u32 GetSharedLosMask(const player_id_t player) = 0;
    316316
    317317    /**
    318318     * Get percent map explored statistics for specified player.
    319319     */
    320     virtual i32 GetPercentMapExplored(player_id_t player) = 0;
     320    virtual i32 GetPercentMapExplored(const player_id_t player) = 0;
    321321
    322322
    323323    /**
  • source/simulation2/components/CCmpPosition.cpp

     
    419419        {
    420420            const CMessageInterpolate& msgData = static_cast<const CMessageInterpolate&> (msg);
    421421
    422             float rotY = m_RotY.ToFloat();
     422            const float rotY = m_RotY.ToFloat();
    423423            float delta = rotY - m_InterpolatedRotY;
    424             // Wrap delta to -M_PI..M_PI
    425             delta = fmodf(delta + (float)M_PI, 2*(float)M_PI); // range -2PI..2PI
    426             if (delta < 0) delta += 2*(float)M_PI; // range 0..2PI
    427             delta -= (float)M_PI; // range -M_PI..M_PI
    428             // Clamp to max rate
    429             float deltaClamped = clamp(delta, -m_RotYSpeed*msgData.deltaSimTime, +m_RotYSpeed*msgData.deltaSimTime);
    430             // Calculate new orientation, in a peculiar way in order to make sure the
    431             // result gets close to m_orientation (rather than being n*2*M_PI out)
    432             m_InterpolatedRotY = rotY + deltaClamped - delta;
     424            if (delta != 0.){
     425                // Wrap delta to -M_PI..M_PI
     426                delta = fmodf(delta + (float)M_PI, 2*(float)M_PI); // range -2PI..2PI
     427                if (delta < 0) delta += 2*(float)M_PI; // range 0..2PI
     428                delta -= (float)M_PI; // range -M_PI..M_PI
     429                // Clamp to max rate
     430                const float deltaClamped = clamp(delta, -m_RotYSpeed*msgData.deltaSimTime, +m_RotYSpeed*msgData.deltaSimTime);
     431                // Calculate new orientation, in a peculiar way in order to make sure the
     432                // result gets close to m_orientation (rather than being n*2*M_PI out)
     433                m_InterpolatedRotY = rotY + deltaClamped - delta;
     434            }
    433435
    434436            break;
    435437        }
  • source/simulation2/components/CCmpObstructionManager.cpp

     
    8484        serialize.NumberFixed_Unbounded("r", value.r);
    8585        serialize.NumberU8_Unbounded("flags", value.flags);
    8686        serialize.NumberU32_Unbounded("group", value.group);
    87     }
     87    };
    8888};
    8989
    9090/**
     
    107107        serialize.NumberU8_Unbounded("flags", value.flags);
    108108        serialize.NumberU32_Unbounded("group", value.group);
    109109        serialize.NumberU32_Unbounded("group2", value.group2);
    110     }
     110    };
    111111};
    112112
    113113class CCmpObstructionManager : public ICmpObstructionManager
     
    116116    static void ClassInit(CComponentManager& componentManager)
    117117    {
    118118        componentManager.SubscribeToMessageType(MT_RenderSubmit); // for debug overlays
    119     }
     119    };
    120120
    121121    DEFAULT_COMPONENT_ALLOCATOR(ObstructionManager)
    122122
     
    517517    /**
    518518     * Return whether the given point is within the world bounds by at least r
    519519     */
    520     bool IsInWorld(entity_pos_t x, entity_pos_t z, entity_pos_t r)
     520    inline bool IsInWorld(const entity_pos_t x, const entity_pos_t z, const entity_pos_t r) const
    521521    {
    522522        return (m_WorldX0+r <= x && x <= m_WorldX1-r && m_WorldZ0+r <= z && z <= m_WorldZ1-r);
    523523    }
     
    525525    /**
    526526     * Return whether the given point is within the world bounds
    527527     */
    528     bool IsInWorld(CFixedVector2D p)
     528    inline bool IsInWorld(const CFixedVector2D& p) const
    529529    {
    530530        return (m_WorldX0 <= p.X && p.X <= m_WorldX1 && m_WorldZ0 <= p.Y && p.Y <= m_WorldZ1);
    531531    }
     
    541541    if (!IsInWorld(x0, z0, r) || !IsInWorld(x1, z1, r))
    542542        return true;
    543543
    544     CFixedVector2D posMin (std::min(x0, x1) - r, std::min(z0, z1) - r);
    545     CFixedVector2D posMax (std::max(x0, x1) + r, std::max(z0, z1) + r);
    546 
    547     std::vector<u32> unitShapes = m_UnitSubdivision.GetInRange(posMin, posMax);
    548     for (size_t i = 0; i < unitShapes.size(); ++i)
     544    const CFixedVector2D posMin (std::min(x0, x1) - r, std::min(z0, z1) - r);
     545    const CFixedVector2D posMax (std::max(x0, x1) + r, std::max(z0, z1) + r);
    549546    {
    550         std::map<u32, UnitShape>::iterator it = m_UnitShapes.find(unitShapes[i]);
    551         ENSURE(it != m_UnitShapes.end());
     547        std::vector<u32> unitShapes;
     548        m_UnitSubdivision.GetInRange(posMin, posMax, unitShapes);
     549        const std::vector<u32>::iterator itEnd = unitShapes.end();
     550        for (std::vector<u32>::iterator itShape = unitShapes.begin(); itShape != itEnd; ++itShape)
     551        {
     552            //std::map<u32, UnitShape>::iterator it = m_UnitShapes.find(unitShapes[i]);
     553            std::map<u32, UnitShape>::iterator it = m_UnitShapes.find(*itShape);
     554            ENSURE(it != m_UnitShapes.end());
    552555
    553         if (!filter.TestShape(UNIT_INDEX_TO_TAG(it->first), it->second.flags, it->second.group, INVALID_ENTITY))
    554             continue;
     556            if (!filter.TestShape(UNIT_INDEX_TO_TAG(it->first), it->second.flags, it->second.group, INVALID_ENTITY))
     557                continue;
    555558
    556         CFixedVector2D center(it->second.x, it->second.z);
    557         CFixedVector2D halfSize(it->second.r + r, it->second.r + r);
    558         if (Geometry::TestRayAASquare(CFixedVector2D(x0, z0) - center, CFixedVector2D(x1, z1) - center, halfSize))
    559             return true;
     559            const CFixedVector2D center(it->second.x, it->second.z);
     560            const CFixedVector2D halfSize(it->second.r + r, it->second.r + r);
     561            if (Geometry::TestRayAASquare(CFixedVector2D(x0, z0) - center, CFixedVector2D(x1, z1) - center, halfSize))
     562                return true;
     563        }       
    560564    }
    561 
    562     std::vector<u32> staticShapes = m_StaticSubdivision.GetInRange(posMin, posMax);
    563     for (size_t i = 0; i < staticShapes.size(); ++i)
    564565    {
    565         std::map<u32, StaticShape>::iterator it = m_StaticShapes.find(staticShapes[i]);
    566         ENSURE(it != m_StaticShapes.end());
     566        std::vector<u32> staticShapes;
     567        m_StaticSubdivision.GetInRange(posMin, posMax, staticShapes);
     568        const std::vector<u32>::iterator itEnd = staticShapes.end();
     569        for (std::vector<u32>::iterator itShape = staticShapes.begin(); itShape != itEnd; ++itShape)
     570        {
     571            std::map<u32, StaticShape>::iterator it = m_StaticShapes.find(*itShape);
     572            ENSURE(it != m_StaticShapes.end());
    567573
    568         if (!filter.TestShape(STATIC_INDEX_TO_TAG(it->first), it->second.flags, it->second.group, it->second.group2))
    569             continue;
     574            if (!filter.TestShape(STATIC_INDEX_TO_TAG(it->first), it->second.flags, it->second.group, it->second.group2))
     575                continue;
    570576
    571         CFixedVector2D center(it->second.x, it->second.z);
    572         CFixedVector2D halfSize(it->second.hw + r, it->second.hh + r);
    573         if (Geometry::TestRaySquare(CFixedVector2D(x0, z0) - center, CFixedVector2D(x1, z1) - center, it->second.u, it->second.v, halfSize))
    574             return true;
     577            const CFixedVector2D center(it->second.x, it->second.z);
     578            const CFixedVector2D halfSize(it->second.hw + r, it->second.hh + r);
     579            if (Geometry::TestRaySquare(CFixedVector2D(x0, z0) - center, CFixedVector2D(x1, z1) - center, it->second.u, it->second.v, halfSize))
     580                return true;
     581        }   
    575582    }
    576583
    577584    return false;
     
    590597
    591598    fixed s, c;
    592599    sincos_approx(a, s, c);
    593     CFixedVector2D u(c, -s);
    594     CFixedVector2D v(s, c);
    595     CFixedVector2D center(x, z);
    596     CFixedVector2D halfSize(w/2, h/2);
     600    const CFixedVector2D u(c, -s);
     601    const CFixedVector2D v(s, c);
     602    const CFixedVector2D center(x, z);
     603    const CFixedVector2D halfSize(w/2, h/2);
    597604
    598605    // Check that all corners are within the world (which means the whole shape must be)
    599606    if (!IsInWorld(center + u.Multiply(halfSize.X) + v.Multiply(halfSize.Y)) ||
     
    607614            return true;
    608615    }
    609616
    610     for (std::map<u32, UnitShape>::iterator it = m_UnitShapes.begin(); it != m_UnitShapes.end(); ++it)
     617    const std::map<u32, UnitShape>::iterator itUEnd = m_UnitShapes.end();
     618    for (std::map<u32, UnitShape>::iterator it = m_UnitShapes.begin(); it != itUEnd; ++it)
    611619    {
    612620        if (!filter.TestShape(UNIT_INDEX_TO_TAG(it->first), it->second.flags, it->second.group, INVALID_ENTITY))
    613621            continue;
     
    623631        }
    624632    }
    625633
    626     for (std::map<u32, StaticShape>::iterator it = m_StaticShapes.begin(); it != m_StaticShapes.end(); ++it)
     634    const std::map<u32, StaticShape>::iterator itSEnd = m_StaticShapes.end();
     635    for (std::map<u32, StaticShape>::iterator it = m_StaticShapes.begin(); it != itSEnd; ++it)
    627636    {
    628637        if (!filter.TestShape(STATIC_INDEX_TO_TAG(it->first), it->second.flags, it->second.group, it->second.group2))
    629638            continue;
    630639
    631         CFixedVector2D center1(it->second.x, it->second.z);
    632         CFixedVector2D halfSize1(it->second.hw, it->second.hh);
     640        const CFixedVector2D center1(it->second.x, it->second.z);
     641        const CFixedVector2D halfSize1(it->second.hw, it->second.hh);
    633642        if (Geometry::TestSquareSquare(center, u, v, halfSize, center1, it->second.u, it->second.v, halfSize1))
    634643        {
    635644            if (out)
     
    664673
    665674    CFixedVector2D center(x, z);
    666675
    667     for (std::map<u32, UnitShape>::iterator it = m_UnitShapes.begin(); it != m_UnitShapes.end(); ++it)
     676    const std::map<u32, UnitShape>::iterator itUEnd = m_UnitShapes.end();
     677    for (std::map<u32, UnitShape>::iterator it = m_UnitShapes.begin(); it != itUEnd; ++it)
    668678    {
    669679        if (!filter.TestShape(UNIT_INDEX_TO_TAG(it->first), it->second.flags, it->second.group, INVALID_ENTITY))
    670680            continue;
    671681
    672         entity_pos_t r1 = it->second.r;
     682        const entity_pos_t r1 = it->second.r;
    673683
    674684        if (!(it->second.x + r1 < x - r || it->second.x - r1 > x + r || it->second.z + r1 < z - r || it->second.z - r1 > z + r))
    675685        {
     
    680690        }
    681691    }
    682692
    683     for (std::map<u32, StaticShape>::iterator it = m_StaticShapes.begin(); it != m_StaticShapes.end(); ++it)
     693    const std::map<u32, StaticShape>::iterator itSEnd = m_StaticShapes.end();
     694    for (std::map<u32, StaticShape>::iterator it = m_StaticShapes.begin(); it != itSEnd; ++it)
    684695    {
    685696        if (!filter.TestShape(STATIC_INDEX_TO_TAG(it->first), it->second.flags, it->second.group, it->second.group2))
    686697            continue;
    687698
    688         CFixedVector2D center1(it->second.x, it->second.z);
     699        const CFixedVector2D center1(it->second.x, it->second.z);
    689700        if (Geometry::PointIsInSquare(center1 - center, it->second.u, it->second.v, CFixedVector2D(it->second.hw + r, it->second.hh + r)))
    690701        {
    691702            if (out)
     
    750761    // so we need to expand by at least 1/sqrt(2) of a tile
    751762    entity_pos_t expandFoundation = (entity_pos_t::FromInt(TERRAIN_TILE_SIZE) * 3) / 4;
    752763
    753     for (std::map<u32, StaticShape>::iterator it = m_StaticShapes.begin(); it != m_StaticShapes.end(); ++it)
     764    const std::map<u32, StaticShape>::iterator itSEnd = m_StaticShapes.end();
     765    for (std::map<u32, StaticShape>::iterator it = m_StaticShapes.begin(); it != itSEnd; ++it)
    754766    {
    755767        CFixedVector2D center(it->second.x, it->second.z);
    756768
     
    776788
    777789        if (it->second.flags & FLAG_BLOCK_FOUNDATION)
    778790        {
    779             CFixedVector2D halfSize(it->second.hw + expandFoundation, it->second.hh + expandFoundation);
    780             CFixedVector2D halfBound = Geometry::GetHalfBoundingBox(it->second.u, it->second.v, halfSize);
     791            const CFixedVector2D halfSize(it->second.hw + expandFoundation, it->second.hh + expandFoundation);
     792            const CFixedVector2D halfBound(Geometry::GetHalfBoundingBox(it->second.u, it->second.v, halfSize));
    781793
    782794            u16 i0, j0, i1, j1;
    783795            NearestTile(center.X - halfBound.X, center.Y - halfBound.Y, i0, j0, grid.m_W, grid.m_H);
     
    795807        }
    796808    }
    797809
    798     for (std::map<u32, UnitShape>::iterator it = m_UnitShapes.begin(); it != m_UnitShapes.end(); ++it)
     810    const std::map<u32, UnitShape>::iterator itUEnd = m_UnitShapes.end();
     811    for (std::map<u32, UnitShape>::iterator it = m_UnitShapes.begin(); it != itUEnd; ++it)
    799812    {
    800         CFixedVector2D center(it->second.x, it->second.z);
     813        const CFixedVector2D center(it->second.x, it->second.z);
    801814
    802815        if (it->second.flags & FLAG_BLOCK_PATHFINDING)
    803816        {
     
    813826
    814827        if (it->second.flags & FLAG_BLOCK_FOUNDATION)
    815828        {
    816             entity_pos_t r = it->second.r + expandFoundation;
     829            const entity_pos_t r = it->second.r + expandFoundation;
    817830
    818831            u16 i0, j0, i1, j1;
    819832            NearestTile(center.X - r, center.Y - r, i0, j0, grid.m_W, grid.m_H);
     
    880893
    881894    ENSURE(x0 <= x1 && z0 <= z1);
    882895
    883     std::vector<u32> unitShapes = m_UnitSubdivision.GetInRange(CFixedVector2D(x0, z0), CFixedVector2D(x1, z1));
    884     for (size_t i = 0; i < unitShapes.size(); ++i)
     896    std::vector<u32> unitShapes;
     897    m_UnitSubdivision.GetInRange(CFixedVector2D(x0, z0), CFixedVector2D(x1, z1), unitShapes);
     898    const std::vector<u32>::iterator  itUEnd = unitShapes.end();
     899    for (std::vector<u32>::iterator itShape = unitShapes.begin(); itShape != itUEnd; ++itShape)
    885900    {
    886         std::map<u32, UnitShape>::iterator it = m_UnitShapes.find(unitShapes[i]);
     901        std::map<u32, UnitShape>::iterator it = m_UnitShapes.find(*itShape);
    887902        ENSURE(it != m_UnitShapes.end());
    888903
    889904        if (!filter.TestShape(UNIT_INDEX_TO_TAG(it->first), it->second.flags, it->second.group, INVALID_ENTITY))
     
    901916        squares.push_back(s);
    902917    }
    903918
    904     std::vector<u32> staticShapes = m_StaticSubdivision.GetInRange(CFixedVector2D(x0, z0), CFixedVector2D(x1, z1));
    905     for (size_t i = 0; i < staticShapes.size(); ++i)
     919    std::vector<u32> staticShapes;
     920    m_StaticSubdivision.GetInRange(CFixedVector2D(x0, z0), CFixedVector2D(x1, z1), staticShapes);
     921    const std::vector<u32>::iterator itSEnd = staticShapes.end();
     922    for (std::vector<u32>::iterator itShape = staticShapes.begin(); itShape != itSEnd; ++itShape)
    906923    {
    907         std::map<u32, StaticShape>::iterator it = m_StaticShapes.find(staticShapes[i]);
     924        //std::map<u32, StaticShape>::iterator it = m_StaticShapes.find(staticShapes[i]);
     925        std::map<u32, StaticShape>::iterator it = m_StaticShapes.find(*itShape);
    908926        ENSURE(it != m_StaticShapes.end());
    909927
    910928        if (!filter.TestShape(STATIC_INDEX_TO_TAG(it->first), it->second.flags, it->second.group, it->second.group2))
     
    981999                (m_WorldX1-m_WorldX0).ToFloat(), (m_WorldZ1-m_WorldZ0).ToFloat(),
    9821000                0, m_DebugOverlayLines.back(), true);
    9831001
    984         for (std::map<u32, UnitShape>::iterator it = m_UnitShapes.begin(); it != m_UnitShapes.end(); ++it)
    9851002        {
    986             m_DebugOverlayLines.push_back(SOverlayLine());
    987             m_DebugOverlayLines.back().m_Color = ((it->second.flags & FLAG_MOVING) ? movingColour : defaultColour);
    988             SimRender::ConstructSquareOnGround(GetSimContext(), it->second.x.ToFloat(), it->second.z.ToFloat(), it->second.r.ToFloat()*2, it->second.r.ToFloat()*2, 0, m_DebugOverlayLines.back(), true);
     1003            const std::map<u32, UnitShape>::iterator itUEnd = m_UnitShapes.end();
     1004            for (std::map<u32, UnitShape>::iterator it = m_UnitShapes.begin(); it != itUEnd; ++it)
     1005            {
     1006                m_DebugOverlayLines.push_back(SOverlayLine());
     1007                m_DebugOverlayLines.back().m_Color = ((it->second.flags & FLAG_MOVING) ? movingColour : defaultColour);
     1008                SimRender::ConstructSquareOnGround(GetSimContext(), it->second.x.ToFloat(), it->second.z.ToFloat(), it->second.r.ToFloat()*2, it->second.r.ToFloat()*2, 0, m_DebugOverlayLines.back(), true);
     1009            }
    9891010        }
    990 
    991         for (std::map<u32, StaticShape>::iterator it = m_StaticShapes.begin(); it != m_StaticShapes.end(); ++it)
    9921011        {
    993             m_DebugOverlayLines.push_back(SOverlayLine());
    994             m_DebugOverlayLines.back().m_Color = defaultColour;
    995             float a = atan2f(it->second.v.X.ToFloat(), it->second.v.Y.ToFloat());
    996             SimRender::ConstructSquareOnGround(GetSimContext(), it->second.x.ToFloat(), it->second.z.ToFloat(), it->second.hw.ToFloat()*2, it->second.hh.ToFloat()*2, a, m_DebugOverlayLines.back(), true);
     1012            const std::map<u32, StaticShape>::iterator itSEnd = m_StaticShapes.end();
     1013            for (std::map<u32, StaticShape>::iterator it = m_StaticShapes.begin(); it != itSEnd; ++it)
     1014            {
     1015                m_DebugOverlayLines.push_back(SOverlayLine());
     1016                m_DebugOverlayLines.back().m_Color = defaultColour;
     1017                float a = atan2f(it->second.v.X.ToFloat(), it->second.v.Y.ToFloat());
     1018                SimRender::ConstructSquareOnGround(GetSimContext(), it->second.x.ToFloat(), it->second.z.ToFloat(), it->second.hw.ToFloat()*2, it->second.hh.ToFloat()*2, a, m_DebugOverlayLines.back(), true);
     1019            }
    9971020        }
    998 
    9991021        m_DebugOverlayDirty = false;
    10001022    }
    10011023
  • source/simulation2/components/CCmpUnitMotion.cpp

     
    521521    /**
    522522     * Do the per-turn movement and other updates.
    523523     */
    524     void Move(fixed dt);
     524    void Move(const fixed dt);
    525525
    526526    /**
    527527     * Decide whether to approximate the given range from a square target as a circle,
    528528     * rather than as a square.
    529529     */
    530     bool ShouldTreatTargetAsCircle(entity_pos_t range, entity_pos_t hw, entity_pos_t hh, entity_pos_t circleRadius);
     530    bool ShouldTreatTargetAsCircle(const entity_pos_t range, const entity_pos_t hw, const entity_pos_t hh, const entity_pos_t circleRadius);
    531531
    532532    /**
    533533     * Computes the current location of our target entity (plus offset).
     
    539539     * Attempts to replace the current path with a straight line to the target
    540540     * entity, if it's close enough and the route is not obstructed.
    541541     */
    542     bool TryGoingStraightToTargetEntity(CFixedVector2D from);
     542    bool TryGoingStraightToTargetEntity(const CFixedVector2D& from);
    543543
    544544    /**
    545545     * Returns whether the target entity has moved more than minDelta since our
    546546     * last path computations, and we're close enough to it to care.
    547547     */
    548     bool CheckTargetMovement(CFixedVector2D from, entity_pos_t minDelta);
     548    bool CheckTargetMovement(const CFixedVector2D&  from, const entity_pos_t minDelta);
    549549
    550550    /**
    551551     * Returns whether the length of the given path, plus the distance from
    552552     * 'from' to the first waypoints, it shorter than minDistance.
    553553     */
    554     bool PathIsShort(const ICmpPathfinder::Path& path, CFixedVector2D from, entity_pos_t minDistance);
     554    bool PathIsShort(const ICmpPathfinder::Path& path, const CFixedVector2D& from, const entity_pos_t minDistance);
    555555
    556556    /**
    557557     * Rotate to face towards the target point, given the current pos
    558558     */
    559     void FaceTowardsPointFromPos(CFixedVector2D pos, entity_pos_t x, entity_pos_t z);
     559    void FaceTowardsPointFromPos(const CFixedVector2D&  pos, const entity_pos_t x, const entity_pos_t z);
    560560
    561561    /**
    562562     * Returns an appropriate obstruction filter for use with path requests.
     
    568568     * Might go in a straight line immediately, or might start an asynchronous
    569569     * path request.
    570570     */
    571     void BeginPathing(CFixedVector2D from, const ICmpPathfinder::Goal& goal);
     571    void BeginPathing(const CFixedVector2D& from, const ICmpPathfinder::Goal& goal);
    572572
    573573    /**
    574574     * Start an asynchronous long path query.
    575575     */
    576     void RequestLongPath(CFixedVector2D from, const ICmpPathfinder::Goal& goal);
     576    void RequestLongPath(const CFixedVector2D& from, const ICmpPathfinder::Goal& goal);
    577577
    578578    /**
    579579     * Start an asynchronous short path query.
    580580     */
    581     void RequestShortPath(CFixedVector2D from, const ICmpPathfinder::Goal& goal, bool avoidMovingUnits);
     581    void RequestShortPath(const CFixedVector2D& from, const ICmpPathfinder::Goal& goal, bool avoidMovingUnits);
    582582
    583583    /**
    584584     * Select a next long waypoint, given the current unit position.
     
    753753    }
    754754}
    755755
    756 void CCmpUnitMotion::Move(fixed dt)
     756void CCmpUnitMotion::Move(const fixed dt)
    757757{
    758758    PROFILE("Move");
    759759
     
    802802        if (!cmpPosition || !cmpPosition->IsInWorld())
    803803            return;
    804804
    805         CFixedVector2D initialPos = cmpPosition->GetPosition2D();
     805        const CFixedVector2D initialPos (cmpPosition->GetPosition2D());
    806806
    807807        // If we're chasing a potentially-moving unit and are currently close
    808808        // enough to its current position, and we can head in a straight line
     
    811811            TryGoingStraightToTargetEntity(initialPos);
    812812
    813813        // Keep track of the current unit's position during the update
    814         CFixedVector2D pos = initialPos;
     814        CFixedVector2D pos (initialPos);
    815815
    816816        // If in formation, run to keep up; otherwise just walk
    817817        // (TODO: support stamina, charging, etc)
     
    824824        // Find the speed factor of the underlying terrain
    825825        // (We only care about the tile we start on - it doesn't matter if we're moving
    826826        // partially onto a much slower/faster tile)
    827         fixed terrainSpeed = cmpPathfinder->GetMovementSpeed(pos.X, pos.Y, m_CostClass);
     827        const fixed terrainSpeed = cmpPathfinder->GetMovementSpeed(pos.X, pos.Y, m_CostClass);
    828828
    829         fixed maxSpeed = basicSpeed.Multiply(terrainSpeed);
     829        const fixed maxSpeed = basicSpeed.Multiply(terrainSpeed);
    830830
    831831        bool wasObstructed = false;
    832832
     
    841841                break;
    842842
    843843            CFixedVector2D target(m_ShortPath.m_Waypoints.back().x, m_ShortPath.m_Waypoints.back().z);
    844             CFixedVector2D offset = target - pos;
     844            CFixedVector2D offset (target - pos);
    845845
    846846            // Face towards the target
    847847            if (!offset.IsZero())
     
    924924            // If we are close to reaching the end of the short path
    925925            // (or have reached it already), try to extend it
    926926
    927             entity_pos_t minDistance = basicSpeed.Multiply(dt) * WAYPOINT_ADVANCE_LOOKAHEAD_TURNS;
     927            const entity_pos_t minDistance = basicSpeed.Multiply(dt) * WAYPOINT_ADVANCE_LOOKAHEAD_TURNS;
    928928            if (PathIsShort(m_ShortPath, pos, minDistance))
    929929            {
    930930                // Start the path extension from the end of this short path
    931931                // (or our current position if no short path)
    932                 CFixedVector2D from = pos;
     932                CFixedVector2D from (pos);
    933933                if (!m_ShortPath.m_Waypoints.empty())
    934934                    from = CFixedVector2D(m_ShortPath.m_Waypoints[0].x, m_ShortPath.m_Waypoints[0].z);
    935935
     
    10101010    return true;
    10111011}
    10121012
    1013 bool CCmpUnitMotion::TryGoingStraightToTargetEntity(CFixedVector2D from)
     1013bool CCmpUnitMotion::TryGoingStraightToTargetEntity(const CFixedVector2D& from)
    10141014{
    10151015    CFixedVector2D targetPos;
    10161016    if (!ComputeTargetPosition(targetPos))
     
    10481048    return true;
    10491049}
    10501050
    1051 bool CCmpUnitMotion::CheckTargetMovement(CFixedVector2D from, entity_pos_t minDelta)
     1051bool CCmpUnitMotion::CheckTargetMovement(const CFixedVector2D& from, entity_pos_t minDelta)
    10521052{
    10531053    CFixedVector2D targetPos;
    10541054    if (!ComputeTargetPosition(targetPos))
     
    10871087    return true;
    10881088}
    10891089
    1090 bool CCmpUnitMotion::PathIsShort(const ICmpPathfinder::Path& path, CFixedVector2D from, entity_pos_t minDistance)
     1090bool CCmpUnitMotion::PathIsShort(const ICmpPathfinder::Path& path, const CFixedVector2D&  from, const entity_pos_t minDistance)
    10911091{
    1092     CFixedVector2D pos = from;
     1092    CFixedVector2D pos (from);
    10931093    entity_pos_t distLeft = minDistance;
    10941094
    1095     for (ssize_t i = (ssize_t)path.m_Waypoints.size()-1; i >= 0; --i)
     1095    const std::vector<ICmpPathfinder::Waypoint>::const_reverse_iterator itEnd = path.m_Waypoints.rend();
     1096    for (std::vector<ICmpPathfinder::Waypoint>::const_reverse_iterator it = path.m_Waypoints.rbegin(); it != itEnd; ++it)
    10961097    {
     1098        const ICmpPathfinder::Waypoint& waypoint = *it;
    10971099        // Check if the next path segment is longer than the requested minimum
    1098         CFixedVector2D waypoint(path.m_Waypoints[i].x, path.m_Waypoints[i].z);
    1099         CFixedVector2D delta = waypoint - pos;
     1100        const CFixedVector2D waypoint_pos(waypoint.x, waypoint.z);
     1101        const CFixedVector2D delta (waypoint_pos - pos);
    11001102        if (delta.CompareLength(distLeft) > 0)
    11011103            return false;
    11021104
    11031105        // Still short enough - prepare to check the next segment
     1106        //todo: perf: reuse sqlenth from just above computation.
    11041107        distLeft -= delta.Length();
    1105         pos = waypoint;
     1108        pos = waypoint_pos;
    11061109    }
    11071110
    11081111    // Reached the end of the path before exceeding minDistance
    11091112    return true;
    11101113}
    11111114
    1112 void CCmpUnitMotion::FaceTowardsPoint(entity_pos_t x, entity_pos_t z)
     1115void CCmpUnitMotion::FaceTowardsPoint(const entity_pos_t x, const entity_pos_t z)
    11131116{
    11141117    CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), GetEntityId());
    11151118    if (!cmpPosition || !cmpPosition->IsInWorld())
    11161119        return;
    11171120
    1118     CFixedVector2D pos = cmpPosition->GetPosition2D();
     1121    const CFixedVector2D pos (cmpPosition->GetPosition2D());
    11191122    FaceTowardsPointFromPos(pos, x, z);
    11201123}
    11211124
    1122 void CCmpUnitMotion::FaceTowardsPointFromPos(CFixedVector2D pos, entity_pos_t x, entity_pos_t z)
     1125void CCmpUnitMotion::FaceTowardsPointFromPos(const CFixedVector2D&  pos, const entity_pos_t x, const entity_pos_t z)
    11231126{
    11241127    CFixedVector2D target(x, z);
    1125     CFixedVector2D offset = target - pos;
     1128    CFixedVector2D offset (target - pos);
    11261129    if (!offset.IsZero())
    11271130    {
    11281131        entity_angle_t angle = atan2_approx(offset.X, offset.Y);
     
    11471150
    11481151
    11491152
    1150 void CCmpUnitMotion::BeginPathing(CFixedVector2D from, const ICmpPathfinder::Goal& goal)
     1153void CCmpUnitMotion::BeginPathing(const CFixedVector2D& from, const ICmpPathfinder::Goal& goal)
    11511154{
    11521155    // Cancel any pending path requests
    11531156    m_ExpectedPathTicket = 0;
     
    11811184    RequestLongPath(from, goal);
    11821185}
    11831186
    1184 void CCmpUnitMotion::RequestLongPath(CFixedVector2D from, const ICmpPathfinder::Goal& goal)
     1187void CCmpUnitMotion::RequestLongPath(const CFixedVector2D& from, const ICmpPathfinder::Goal& goal)
    11851188{
    11861189    CmpPtr<ICmpPathfinder> cmpPathfinder(GetSimContext(), SYSTEM_ENTITY);
    11871190    if (!cmpPathfinder)
     
    11921195    m_ExpectedPathTicket = cmpPathfinder->ComputePathAsync(from.X, from.Y, goal, m_PassClass, m_CostClass, GetEntityId());
    11931196}
    11941197
    1195 void CCmpUnitMotion::RequestShortPath(CFixedVector2D from, const ICmpPathfinder::Goal& goal, bool avoidMovingUnits)
     1198void CCmpUnitMotion::RequestShortPath(const CFixedVector2D&  from, const ICmpPathfinder::Goal& goal, const bool avoidMovingUnits)
    11961199{
    11971200    CmpPtr<ICmpPathfinder> cmpPathfinder(GetSimContext(), SYSTEM_ENTITY);
    11981201    if (!cmpPathfinder)
     
    12011204    m_ExpectedPathTicket = cmpPathfinder->ComputeShortPathAsync(from.X, from.Y, m_Radius, SHORT_PATH_SEARCH_RANGE, goal, m_PassClass, avoidMovingUnits, m_TargetEntity, GetEntityId());
    12021205}
    12031206
    1204 bool CCmpUnitMotion::PickNextLongWaypoint(const CFixedVector2D& pos, bool avoidMovingUnits)
     1207bool CCmpUnitMotion::PickNextLongWaypoint(const CFixedVector2D& pos, const bool avoidMovingUnits)
    12051208{
    12061209    // If there's no long path, we can't pick the next waypoint from it
    12071210    if (m_LongPath.m_Waypoints.empty())
     
    12521255}
    12531256
    12541257
    1255 bool CCmpUnitMotion::MoveToPointRange(entity_pos_t x, entity_pos_t z, entity_pos_t minRange, entity_pos_t maxRange)
     1258bool CCmpUnitMotion::MoveToPointRange(const entity_pos_t x, const entity_pos_t z, const entity_pos_t minRange, const entity_pos_t maxRange)
    12561259{
    12571260    PROFILE("MoveToPointRange");
    12581261
     
    13381341    return true;
    13391342}
    13401343
    1341 bool CCmpUnitMotion::IsInPointRange(entity_pos_t x, entity_pos_t z, entity_pos_t minRange, entity_pos_t maxRange)
     1344bool CCmpUnitMotion::IsInPointRange(const entity_pos_t x, const entity_pos_t z, const entity_pos_t minRange, const entity_pos_t maxRange)
    13421345{
    13431346    CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), GetEntityId());
    13441347    if (!cmpPosition || !cmpPosition->IsInWorld())
    13451348        return false;
    13461349
    1347     CFixedVector2D pos = cmpPosition->GetPosition2D();
     1350    const CFixedVector2D pos (cmpPosition->GetPosition2D());
    13481351
    13491352    bool hasObstruction = false;
    13501353    CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSimContext(), SYSTEM_ENTITY);
     
    13551358    if (minRange.IsZero() && maxRange.IsZero() && hasObstruction)
    13561359    {
    13571360        // Handle the non-ranged mode:
    1358         CFixedVector2D halfSize(obstruction.hw, obstruction.hh);
    1359         entity_pos_t distance = Geometry::DistanceToSquare(pos - CFixedVector2D(obstruction.x, obstruction.z), obstruction.u, obstruction.v, halfSize);
     1361        const CFixedVector2D halfSize(obstruction.hw, obstruction.hh);
     1362        const entity_pos_t distance = Geometry::DistanceToSquare(pos - CFixedVector2D(obstruction.x, obstruction.z), obstruction.u, obstruction.v, halfSize);
    13601363
    13611364        // See if we're too close to the target square
    13621365        if (distance < minRange)
     
    13701373    }
    13711374    else
    13721375    {
    1373         entity_pos_t distance = (pos - CFixedVector2D(x, z)).Length();
     1376        const entity_pos_t distance = (pos - CFixedVector2D(x, z)).Length();
    13741377
    13751378        if (distance < minRange)
    13761379        {
     
    13871390    }
    13881391}
    13891392
    1390 bool CCmpUnitMotion::ShouldTreatTargetAsCircle(entity_pos_t range, entity_pos_t hw, entity_pos_t hh, entity_pos_t circleRadius)
     1393bool CCmpUnitMotion::ShouldTreatTargetAsCircle(const entity_pos_t range, const entity_pos_t hw, const entity_pos_t hh, const entity_pos_t circleRadius)
    13911394{
    13921395    // Given a square, plus a target range we should reach, the shape at that distance
    13931396    // is a round-cornered square which we can approximate as either a circle or as a square.
     
    14021405    return (errCircle < errSquare);
    14031406}
    14041407
    1405 bool CCmpUnitMotion::MoveToTargetRange(entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange)
     1408bool CCmpUnitMotion::MoveToTargetRange(const entity_id_t target, const entity_pos_t minRange, const entity_pos_t maxRange)
    14061409{
    14071410    PROFILE("MoveToTargetRange");
    14081411
     
    15461549    }
    15471550}
    15481551
    1549 bool CCmpUnitMotion::IsInTargetRange(entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange)
     1552bool CCmpUnitMotion::IsInTargetRange(const entity_id_t target, const entity_pos_t minRange, const entity_pos_t maxRange)
    15501553{
    15511554    // This function closely mirrors MoveToTargetRange - it needs to return true
    15521555    // after that Move has completed
     
    16121615    }
    16131616}
    16141617
    1615 void CCmpUnitMotion::MoveToFormationOffset(entity_id_t target, entity_pos_t x, entity_pos_t z)
     1618void CCmpUnitMotion::MoveToFormationOffset(const entity_id_t target, const entity_pos_t x, const entity_pos_t z)
    16161619{
    16171620    CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), target);
    16181621    if (!cmpPosition || !cmpPosition->IsInWorld())
    16191622        return;
    16201623
    1621     CFixedVector2D pos = cmpPosition->GetPosition2D();
     1624    CFixedVector2D pos (cmpPosition->GetPosition2D());
    16221625
    16231626    ICmpPathfinder::Goal goal;
    16241627    goal.type = ICmpPathfinder::Goal::POINT;
  • source/simulation2/components/tests/test_Pathfinder.h

     
    6868        CMapReader* mapReader = new CMapReader(); // it'll call "delete this" itself
    6969
    7070        LDR_BeginRegistering();
    71         mapReader->LoadMap(L"maps/scenarios/Median Oasis.pmp", &terrain, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     71        mapReader->LoadMap(L"maps/scenarios/Median Oasis 01.pmp", &terrain, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    7272            &sim2, &sim2.GetSimContext(), -1, false);
    7373        LDR_EndRegistering();
    7474        TS_ASSERT_OK(LDR_NonprogressiveLoad());
     
    9090            printf("%d: %f %f\n", (int)i, path.m_Waypoints[i].x.ToDouble(), path.m_Waypoints[i].z.ToDouble());
    9191#endif
    9292
    93         double t = timer_Time();
    9493
    9594        srand(1234);
     95
     96        std::vector<ICmpPathfinder::Goal> goals;
     97
     98        std::vector<entity_pos_t> x0s;
     99        std::vector<entity_pos_t> z0s;
    96100        for (size_t j = 0; j < 1024*2; ++j)
    97101        {
    98102            entity_pos_t x0 = entity_pos_t::FromInt(rand() % 512);
     
    100104            entity_pos_t x1 = x0 + entity_pos_t::FromInt(rand() % 64);
    101105            entity_pos_t z1 = z0 + entity_pos_t::FromInt(rand() % 64);
    102106            ICmpPathfinder::Goal goal = { ICmpPathfinder::Goal::POINT, x1, z1 };
     107            x0s.push_back(x0);
     108            z0s.push_back(z0);
     109            goals.push_back(goal);
     110        }
    103111
    104             ICmpPathfinder::Path path;
    105             cmp->ComputePath(x0, z0, goal, cmp->GetPassabilityClass("default"), cmp->GetCostClass("default"), path);
     112        double t = timer_Time();
     113
     114       
     115        ICmpPathfinder::Path path;
     116        for (size_t j = 0; j < 1024*2; ++j)
     117        {
     118            cmp->ComputePath(x0s[j], z0s[j], goals[j], cmp->GetPassabilityClass("default"), cmp->GetCostClass("default"), path);
    106119        }
    107120
    108121        t = timer_Time() - t;
    109         printf("[%f]", t);
     122        printf("\nTestCmpPathfinder ComputePath[%f]", t);
    110123    }
    111124
    112125    void test_performance_short_DISABLED()
     
    124137        CmpPtr<ICmpPathfinder> cmpPathfinder(sim2, SYSTEM_ENTITY);
    125138
    126139        srand(0);
     140
    127141        for (size_t i = 0; i < 200; ++i)
    128142        {
    129143            fixed x = fixed::FromFloat(1.5f*range.ToFloat() * rand()/(float)RAND_MAX);
     
    131145//          printf("# %f %f\n", x.ToFloat(), z.ToFloat());
    132146            cmpObstructionMan->AddUnitShape(INVALID_ENTITY, x, z, fixed::FromInt(2), 0, INVALID_ENTITY);
    133147        }
     148           
     149        double t = timer_Time();
    134150
    135         NullObstructionFilter filter;
    136         ICmpPathfinder::Goal goal = { ICmpPathfinder::Goal::POINT, range, range };
    137         ICmpPathfinder::Path path;
    138         cmpPathfinder->ComputeShortPath(filter, range/3, range/3, fixed::FromInt(2), range, goal, 0, path);
    139         for (size_t i = 0; i < path.m_Waypoints.size(); ++i)
    140             printf("# %d: %f %f\n", (int)i, path.m_Waypoints[i].x.ToFloat(), path.m_Waypoints[i].z.ToFloat());
     151        for (size_t j = 0; j < 1024*2; ++j)
     152        {
     153
     154            NullObstructionFilter filter;
     155            ICmpPathfinder::Goal goal = { ICmpPathfinder::Goal::POINT, range, range };
     156            ICmpPathfinder::Path path;
     157
     158            cmpPathfinder->ComputeShortPath(filter, range/3, range/3, fixed::FromInt(2), range, goal, 0, path);
     159        }
     160           
     161        t = timer_Time() - t;
     162       
     163        printf("\nTestCmpPathfinder ComputeShortPath[%f]\n", t);
     164        {
     165            NullObstructionFilter filter;
     166            ICmpPathfinder::Goal goal = { ICmpPathfinder::Goal::POINT, range, range };
     167            ICmpPathfinder::Path path;
     168
     169            cmpPathfinder->ComputeShortPath(filter, range/3, range/3, fixed::FromInt(2), range, goal, 0, path);
     170                for (size_t i = 0; i < path.m_Waypoints.size(); ++i)
     171                    printf("# %d: %f %f\n", (int)i, path.m_Waypoints[i].x.ToFloat(), path.m_Waypoints[i].z.ToFloat());
     172        }
    141173    }
    142174};
  • source/simulation2/components/CCmpPathfinder_Vertex.cpp

     
    6363 * Therefore it must continue to a vertex in the BR quadrant (so this vertex is in
    6464 * *that* vertex's TL quadrant).
    6565 *
    66  * That lets us significantly reduce the search space by quickly discarding vertexes
     66 * That lets us significantly reduce the search space by quickly discarding vertices
    6767 * from the wrong quadrants.
    6868 *
    6969 * (This causes badness if the path starts from inside the shape, so we add some hacks
     
    8282static const u8 QUADRANT_ALL = QUADRANT_BLTR|QUADRANT_TLBR;
    8383
    8484// A vertex around the corners of an obstruction
    85 // (paths will be sequences of these vertexes)
     85// (paths will be sequences of these vertices)
    8686struct Vertex
    8787{
    8888    enum
     
    118118    fixed c1;
    119119};
    120120
    121 // When computing vertexes to insert into the search graph,
    122 // add a small delta so that the vertexes of an edge don't get interpreted
     121// When computing vertices to insert into the search graph,
     122// add a small delta so that the vertices of an edge don't get interpreted
    123123// as crossing the edge (given minor numerical inaccuracies)
    124124static const entity_pos_t EDGE_EXPAND_DELTA = entity_pos_t::FromInt(1)/4;
    125125
     
    127127 * Check whether a ray from 'a' to 'b' crosses any of the edges.
    128128 * (Edges are one-sided so it's only considered a cross if going from front to back.)
    129129 */
    130 inline static bool CheckVisibility(CFixedVector2D a, CFixedVector2D b, const std::vector<Edge>& edges)
     130inline static bool CheckVisibility(const CFixedVector2D& a, const CFixedVector2D& b, const CFixedVector2D& abn, const std::vector<Edge>& edges)
    131131{
    132     CFixedVector2D abn = (b - a).Perpendicular();
    133 
     132    fixed s;
    134133    // Edges of general non-axis-aligned shapes
    135     for (size_t i = 0; i < edges.size(); ++i)
     134    const std::vector<Edge>::const_iterator itEnd = edges.end();
     135    for (std::vector<Edge>::const_iterator it = edges.begin(); it != itEnd; ++it)
    136136    {
    137         CFixedVector2D p0 = edges[i].p0;
    138         CFixedVector2D p1 = edges[i].p1;
     137        const Edge e = *it;
     138        const CFixedVector2D& p0 (e.p0);
    139139
    140         CFixedVector2D d = (p1 - p0).Perpendicular();
     140        // The ray is crossing the infinitely-extended edge from in front to behind.
     141        // Check the finite edge is crossing the infinitely-extended ray too.
     142        // (Given the previous tests, it can only be crossing in one direction.)
     143        s = p0.SubAndDot(a, abn);
     144        if (s > fixed::Zero())
     145            continue;
    141146
     147        const CFixedVector2D& p1 (e.p1);
     148
     149        s = p1.SubAndDot(a, abn);
     150        if (s < fixed::Zero())
     151            continue;
     152
     153        const CFixedVector2D d ((p1 - p0).Perpendicular());
     154
    142155        // If 'a' is behind the edge, we can't cross
    143         fixed q = (a - p0).Dot(d);
    144         if (q < fixed::Zero())
     156        s = a.SubAndDot(p0, d);
     157        if (s < fixed::Zero())
    145158            continue;
    146159
    147160        // If 'b' is in front of the edge, we can't cross
    148         fixed r = (b - p0).Dot(d);
    149         if (r > fixed::Zero())
    150             continue;
    151 
    152         // The ray is crossing the infinitely-extended edge from in front to behind.
    153         // Check the finite edge is crossing the infinitely-extended ray too.
    154         // (Given the previous tests, it can only be crossing in one direction.)
    155         fixed s = (p0 - a).Dot(abn);
     161        s = b.SubAndDot(p0, d);
    156162        if (s > fixed::Zero())
    157163            continue;
    158164
    159         fixed t = (p1 - a).Dot(abn);
    160         if (t < fixed::Zero())
    161             continue;
    162 
    163165        return false;
    164166    }
    165167
     
    170172// (These are specialised versions of the general unaligned edge code.
    171173// They assume the caller has already excluded edges for which 'a' is
    172174// on the wrong side.)
    173 
    174 inline static bool CheckVisibilityLeft(CFixedVector2D a, CFixedVector2D b, const std::vector<EdgeAA>& edges)
     175inline static bool CheckVisibilityLeft(const CFixedVector2D& a, const CFixedVector2D& b, const CFixedVector2D& abn, const std::vector<EdgeAA>& edges)
    175176{
    176177    if (a.X >= b.X)
    177178        return true;
    178 
    179     CFixedVector2D abn = (b - a).Perpendicular();
    180 
    181     for (size_t i = 0; i < edges.size(); ++i)
     179    fixed s;
     180    const std::vector<EdgeAA>::const_iterator itEnd = edges.end();
     181    for (std::vector<EdgeAA>::const_iterator it = edges.begin(); it != itEnd; ++it)
    182182    {
    183         if (b.X < edges[i].p0.X)
    184             continue;
    185 
    186         CFixedVector2D p0 (edges[i].p0.X, edges[i].c1);
    187         fixed s = (p0 - a).Dot(abn);
    188         if (s > fixed::Zero())
    189             continue;
    190 
    191         CFixedVector2D p1 (edges[i].p0.X, edges[i].p0.Y);
    192         fixed t = (p1 - a).Dot(abn);
    193         if (t < fixed::Zero())
    194             continue;
    195 
    196         return false;
     183        const EdgeAA& e = *it;
     184        if ( b.X >= e.p0.X){ // diff line from right
     185            s = a.SubFromAndDot(e.p0.X, e.c1, abn);
     186            if (s.value <= 0){
     187                s = a.SubFromAndDot(e.p0.X, e.p0.Y, abn);
     188                if (s.value >= 0){
     189                    return false;
     190                }
     191            }
     192        }
    197193    }
    198194
    199195    return true;
    200196}
    201197
    202 inline static bool CheckVisibilityRight(CFixedVector2D a, CFixedVector2D b, const std::vector<EdgeAA>& edges)
     198inline static bool CheckVisibilityRight(const CFixedVector2D& a, const CFixedVector2D& b, const CFixedVector2D& abn,const std::vector<EdgeAA>& edges)
    203199{
    204200    if (a.X <= b.X)
    205201        return true;
    206 
    207     CFixedVector2D abn = (b - a).Perpendicular();
    208 
    209     for (size_t i = 0; i < edges.size(); ++i)
     202    fixed s;
     203    const std::vector<EdgeAA>::const_iterator itEnd = edges.end();
     204    for (std::vector<EdgeAA>::const_iterator it = edges.begin(); it != itEnd; ++it)
    210205    {
    211         if (b.X > edges[i].p0.X)
    212             continue;
    213 
    214         CFixedVector2D p0 (edges[i].p0.X, edges[i].c1);
    215         fixed s = (p0 - a).Dot(abn);
    216         if (s > fixed::Zero())
    217             continue;
    218 
    219         CFixedVector2D p1 (edges[i].p0.X, edges[i].p0.Y);
    220         fixed t = (p1 - a).Dot(abn);
    221         if (t < fixed::Zero())
    222             continue;
    223 
    224         return false;
     206        const EdgeAA& e = *it;
     207        if ( b.X <= e.p0.X){ // diff line from left
     208            s = a.SubFromAndDot(e.p0.X, e.c1, abn);
     209            if (s.value <= 0){
     210                s = a.SubFromAndDot(e.p0.X, e.p0.Y, abn);
     211                if (s.value >= 0){
     212                    return false;
     213                }
     214            }
     215        }
    225216    }
    226217
    227218    return true;
    228219}
    229220
    230 inline static bool CheckVisibilityBottom(CFixedVector2D a, CFixedVector2D b, const std::vector<EdgeAA>& edges)
     221inline static bool CheckVisibilityBottom(const CFixedVector2D& a, const CFixedVector2D& b, const CFixedVector2D& abn, const std::vector<EdgeAA>& edges)
    231222{
    232223    if (a.Y >= b.Y)
    233224        return true;
    234 
    235     CFixedVector2D abn = (b - a).Perpendicular();
    236 
    237     for (size_t i = 0; i < edges.size(); ++i)
     225    fixed s;
     226    const std::vector<EdgeAA>::const_iterator itEnd = edges.end();
     227    for (std::vector<EdgeAA>::const_iterator it = edges.begin(); it != itEnd; ++it)
    238228    {
    239         if (b.Y < edges[i].p0.Y)
    240             continue;
    241 
    242         CFixedVector2D p0 (edges[i].p0.X, edges[i].p0.Y);
    243         fixed s = (p0 - a).Dot(abn);
    244         if (s > fixed::Zero())
    245             continue;
    246 
    247         CFixedVector2D p1 (edges[i].c1, edges[i].p0.Y);
    248         fixed t = (p1 - a).Dot(abn);
    249         if (t < fixed::Zero())
    250             continue;
    251 
    252         return false;
     229        const EdgeAA& e = *it;
     230        if ( b.Y >= e.p0.Y){ // diff line from top
     231            s = a.SubFromAndDot(e.p0.X, e.p0.Y, abn);
     232            if (s.value <= 0){
     233                s = a.SubFromAndDot(e.c1, e.p0.Y, abn);
     234                if (s.value >= 0){
     235                    return false;
     236                }
     237            }
     238        }
    253239    }
    254240
    255241    return true;
    256242}
    257243
    258 inline static bool CheckVisibilityTop(CFixedVector2D a, CFixedVector2D b, const std::vector<EdgeAA>& edges)
     244inline static bool CheckVisibilityTop(const CFixedVector2D& a, const CFixedVector2D& b, const CFixedVector2D& abn,const std::vector<EdgeAA>& edges)
    259245{
    260246    if (a.Y <= b.Y)
    261247        return true;
    262 
    263     CFixedVector2D abn = (b - a).Perpendicular();
    264 
    265     for (size_t i = 0; i < edges.size(); ++i)
     248   
     249    fixed s;
     250    const std::vector<EdgeAA>::const_iterator itEnd = edges.end();
     251    for (std::vector<EdgeAA>::const_iterator it = edges.begin(); it != itEnd; ++it)
    266252    {
    267         if (b.Y > edges[i].p0.Y)
    268             continue;
     253        const EdgeAA& e = *it;
     254        if ( b.Y <= e.p0.Y){ // diff line from bottom
     255            s = a.SubFromAndDot(e.p0.X, e.p0.Y, abn);
     256            if (s.value <= 0){
     257                s = a.SubFromAndDot(e.c1, e.p0.Y, abn);
     258                if (s.value >= 0){
     259                    return false;
     260                }
     261            }
     262        }
     263    }
    269264
    270         CFixedVector2D p0 (edges[i].p0.X, edges[i].p0.Y);
    271         fixed s = (p0 - a).Dot(abn);
    272         if (s > fixed::Zero())
    273             continue;
    274265
    275         CFixedVector2D p1 (edges[i].c1, edges[i].p0.Y);
    276         fixed t = (p1 - a).Dot(abn);
    277         if (t < fixed::Zero())
    278             continue;
    279 
    280         return false;
    281     }
    282 
    283266    return true;
    284267}
    285268
    286269
    287 static CFixedVector2D NearestPointOnGoal(CFixedVector2D pos, const CCmpPathfinder::Goal& goal)
     270
     271static CFixedVector2D NearestPointOnGoal(const CFixedVector2D& pos, const CCmpPathfinder::Goal& goal)
    288272{
    289     CFixedVector2D g(goal.x, goal.z);
     273    const CFixedVector2D g(goal.x, goal.z);
    290274
    291275    switch (goal.type)
    292276    {
     
    306290
    307291    case CCmpPathfinder::Goal::SQUARE:
    308292    {
    309         CFixedVector2D halfSize(goal.hw, goal.hh);
    310         CFixedVector2D d = pos - g;
     293        const CFixedVector2D halfSize(goal.hw, goal.hh);
     294        const CFixedVector2D d(pos - g);
    311295        return g + Geometry::NearestPointOnSquare(d, goal.u, goal.v, halfSize);
    312296    }
    313297
     
    317301    }
    318302}
    319303
    320 CFixedVector2D CCmpPathfinder::GetNearestPointOnGoal(CFixedVector2D pos, const CCmpPathfinder::Goal& goal)
     304CFixedVector2D CCmpPathfinder::GetNearestPointOnGoal(const CFixedVector2D& pos, const CCmpPathfinder::Goal& goal) const
    321305{
    322306    return NearestPointOnGoal(pos, goal);
    323307    // (It's intentional that we don't put the implementation inside this
     
    333317    enum { TOP, BOTTOM, LEFT, RIGHT } dir;
    334318};
    335319
    336 static void AddTerrainEdges(std::vector<Edge>& edgesAA, std::vector<Vertex>& vertexes,
    337     u16 i0, u16 j0, u16 i1, u16 j1, fixed r,
    338     ICmpPathfinder::pass_class_t passClass, const Grid<TerrainTile>& terrain)
     320std::vector<TileEdge> tileEdges;
     321
     322static void AddTerrainEdges(std::vector<Edge>& edgesAA, std::vector<Vertex>& vertices,
     323    const u16 i0, const u16 j0, const u16 i1, const u16 j1, const fixed r,
     324    const ICmpPathfinder::pass_class_t passClass, const Grid<TerrainTile>& terrain)
    339325{
    340326    PROFILE("AddTerrainEdges");
    341327
    342     std::vector<TileEdge> tileEdges;
     328    tileEdges.clear();
     329    // Find all edges between tiles of differently passability statuses
    343330
    344     // Find all edges between tiles of differently passability statuses
     331    bool any;
     332    const u16 terrainW = terrain.m_W;
     333    const u16 terrainmWOne = terrainW-1;
     334    const u16 terrainmHOne = terrain.m_H-1;
     335    const TerrainTile * const __restrict  data = terrain.m_Data;
    345336    for (u16 j = j0; j <= j1; ++j)
    346337    {
     338        const bool jInsideUp = j < terrainmHOne;
     339        const bool jInsideDown = j != 0;
     340        const u32 jPos = j*terrainW;
    347341        for (u16 i = i0; i <= i1; ++i)
    348342        {
    349             if (!IS_TERRAIN_PASSABLE(terrain.get(i, j), passClass))
     343            if (!IS_TERRAIN_PASSABLE(data[i+jPos], passClass))
    350344            {
    351                 bool any = false; // whether we're adding any edges of this tile
     345                any = false; // whether we're adding any edges of this tile
    352346
    353                 if (j > 0 && IS_TERRAIN_PASSABLE(terrain.get(i, j-1), passClass))
     347                if (jInsideDown && IS_TERRAIN_PASSABLE(data[i+jPos-terrainW], passClass))
    354348                {
    355                     TileEdge e = { i, j, TileEdge::BOTTOM };
     349                    const TileEdge e = { i, j, TileEdge::BOTTOM };
    356350                    tileEdges.push_back(e);
    357351                    any = true;
    358352                }
    359353
    360                 if (j < terrain.m_H-1 && IS_TERRAIN_PASSABLE(terrain.get(i, j+1), passClass))
     354                if (jInsideUp && IS_TERRAIN_PASSABLE(data[i+jPos+terrainW], passClass))
    361355                {
    362                     TileEdge e = { i, j, TileEdge::TOP };
     356                    const TileEdge e = { i, j, TileEdge::TOP };
    363357                    tileEdges.push_back(e);
    364358                    any = true;
    365359                }
    366360
    367                 if (i > 0 && IS_TERRAIN_PASSABLE(terrain.get(i-1, j), passClass))
     361                if (i != 0 && IS_TERRAIN_PASSABLE(data[i+jPos-1], passClass))
    368362                {
    369                     TileEdge e = { i, j, TileEdge::LEFT };
     363                    const TileEdge e = { i, j, TileEdge::LEFT };
    370364                    tileEdges.push_back(e);
    371365                    any = true;
    372366                }
    373367
    374                 if (i < terrain.m_W-1 && IS_TERRAIN_PASSABLE(terrain.get(i+1, j), passClass))
     368                if (i < terrainmWOne && IS_TERRAIN_PASSABLE(data[i+jPos+1], passClass))
    375369                {
    376                     TileEdge e = { i, j, TileEdge::RIGHT };
     370                    const TileEdge e = { i, j, TileEdge::RIGHT };
    377371                    tileEdges.push_back(e);
    378372                    any = true;
    379373                }
     
    382376                // (The inner edges are redundant but it's easier than trying to split the squares apart.)
    383377                if (any)
    384378                {
    385                     CFixedVector2D v0 = CFixedVector2D(fixed::FromInt(i * (int)TERRAIN_TILE_SIZE) - r, fixed::FromInt(j * (int)TERRAIN_TILE_SIZE) - r);
    386                     CFixedVector2D v1 = CFixedVector2D(fixed::FromInt((i+1) * (int)TERRAIN_TILE_SIZE) + r, fixed::FromInt((j+1) * (int)TERRAIN_TILE_SIZE) + r);
    387                     Edge e = { v0, v1 };
     379                    const CFixedVector2D v0 (fixed::FromInt(i * (int)TERRAIN_TILE_SIZE) - r, fixed::FromInt(j * (int)TERRAIN_TILE_SIZE) - r);
     380                    const CFixedVector2D v1 (fixed::FromInt((i+1) * (int)TERRAIN_TILE_SIZE) + r, fixed::FromInt((j+1) * (int)TERRAIN_TILE_SIZE) + r);
     381                    const Edge e = { v0, v1 };
    388382                    edgesAA.push_back(e);
    389383                }
    390384            }
     
    396390    // TODO: for efficiency (minimising the A* search space), we should coalesce adjoining edges
    397391
    398392    // Add all the tile outer edges to the search vertex lists
    399     for (size_t n = 0; n < tileEdges.size(); ++n)
    400     {
    401         u16 i = tileEdges[n].i;
    402         u16 j = tileEdges[n].j;
    403         CFixedVector2D v0, v1;
    404         Vertex vert;
    405         vert.status = Vertex::UNEXPLORED;
    406         vert.quadOutward = QUADRANT_ALL;
    407393
    408         switch (tileEdges[n].dir)
     394    Vertex vert;
     395    vert.status = Vertex::UNEXPLORED;
     396    vert.quadOutward = QUADRANT_ALL;
     397    const std::vector<TileEdge>::const_iterator itEnd = tileEdges.end();
     398    for (std::vector<TileEdge>::const_iterator it = tileEdges.begin(); it != itEnd; ++it)
     399    {       
     400        const TileEdge& tileEdge = *it;
     401        const u16 i = tileEdge.i;
     402        const u16 j = tileEdge.j;
     403
     404        switch (tileEdge.dir)
    409405        {
    410406        case TileEdge::BOTTOM:
    411407        {
    412             v0 = CFixedVector2D(fixed::FromInt(i * (int)TERRAIN_TILE_SIZE) - r, fixed::FromInt(j * (int)TERRAIN_TILE_SIZE) - r);
    413             v1 = CFixedVector2D(fixed::FromInt((i+1) * (int)TERRAIN_TILE_SIZE) + r, fixed::FromInt(j * (int)TERRAIN_TILE_SIZE) - r);
    414             vert.p.X = v0.X - EDGE_EXPAND_DELTA; vert.p.Y = v0.Y - EDGE_EXPAND_DELTA; vert.quadInward = QUADRANT_TR; vertexes.push_back(vert);
    415             vert.p.X = v1.X + EDGE_EXPAND_DELTA; vert.p.Y = v1.Y - EDGE_EXPAND_DELTA; vert.quadInward = QUADRANT_TL; vertexes.push_back(vert);
     408            const CFixedVector2D v0 (fixed::FromInt(i * (int)TERRAIN_TILE_SIZE) - r, fixed::FromInt(j * (int)TERRAIN_TILE_SIZE) - r);
     409            const CFixedVector2D v1 (fixed::FromInt((i+1) * (int)TERRAIN_TILE_SIZE) + r, fixed::FromInt(j * (int)TERRAIN_TILE_SIZE) - r);
     410            vert.p.X = v0.X - EDGE_EXPAND_DELTA; vert.p.Y = v0.Y - EDGE_EXPAND_DELTA; vert.quadInward = QUADRANT_TR; vertices.push_back(vert);
     411            vert.p.X = v1.X + EDGE_EXPAND_DELTA; vert.p.Y = v1.Y - EDGE_EXPAND_DELTA; vert.quadInward = QUADRANT_TL; vertices.push_back(vert);
    416412            break;
    417413        }
    418414        case TileEdge::TOP:
    419415        {
    420             v0 = CFixedVector2D(fixed::FromInt((i+1) * (int)TERRAIN_TILE_SIZE) + r, fixed::FromInt((j+1) * (int)TERRAIN_TILE_SIZE) + r);
    421             v1 = CFixedVector2D(fixed::FromInt(i * (int)TERRAIN_TILE_SIZE) - r, fixed::FromInt((j+1) * (int)TERRAIN_TILE_SIZE) + r);
    422             vert.p.X = v0.X + EDGE_EXPAND_DELTA; vert.p.Y = v0.Y + EDGE_EXPAND_DELTA; vert.quadInward = QUADRANT_BL; vertexes.push_back(vert);
    423             vert.p.X = v1.X - EDGE_EXPAND_DELTA; vert.p.Y = v1.Y + EDGE_EXPAND_DELTA; vert.quadInward = QUADRANT_BR; vertexes.push_back(vert);
     416            const CFixedVector2D v0 (fixed::FromInt((i+1) * (int)TERRAIN_TILE_SIZE) + r, fixed::FromInt((j+1) * (int)TERRAIN_TILE_SIZE) + r);
     417            const CFixedVector2D v1 (fixed::FromInt(i * (int)TERRAIN_TILE_SIZE) - r, fixed::FromInt((j+1) * (int)TERRAIN_TILE_SIZE) + r);
     418            vert.p.X = v0.X + EDGE_EXPAND_DELTA; vert.p.Y = v0.Y + EDGE_EXPAND_DELTA; vert.quadInward = QUADRANT_BL; vertices.push_back(vert);
     419            vert.p.X = v1.X - EDGE_EXPAND_DELTA; vert.p.Y = v1.Y + EDGE_EXPAND_DELTA; vert.quadInward = QUADRANT_BR; vertices.push_back(vert);
    424420            break;
    425421        }
    426422        case TileEdge::LEFT:
    427423        {
    428             v0 = CFixedVector2D(fixed::FromInt(i * (int)TERRAIN_TILE_SIZE) - r, fixed::FromInt((j+1) * (int)TERRAIN_TILE_SIZE) + r);
    429             v1 = CFixedVector2D(fixed::FromInt(i * (int)TERRAIN_TILE_SIZE) - r, fixed::FromInt(j * (int)TERRAIN_TILE_SIZE) - r);
    430             vert.p.X = v0.X - EDGE_EXPAND_DELTA; vert.p.Y = v0.Y + EDGE_EXPAND_DELTA; vert.quadInward = QUADRANT_BR; vertexes.push_back(vert);
    431             vert.p.X = v1.X - EDGE_EXPAND_DELTA; vert.p.Y = v1.Y - EDGE_EXPAND_DELTA; vert.quadInward = QUADRANT_TR; vertexes.push_back(vert);
     424            const CFixedVector2D v0 (fixed::FromInt(i * (int)TERRAIN_TILE_SIZE) - r, fixed::FromInt((j+1) * (int)TERRAIN_TILE_SIZE) + r);
     425            const CFixedVector2D v1 (fixed::FromInt(i * (int)TERRAIN_TILE_SIZE) - r, fixed::FromInt(j * (int)TERRAIN_TILE_SIZE) - r);
     426            vert.p.X = v0.X - EDGE_EXPAND_DELTA; vert.p.Y = v0.Y + EDGE_EXPAND_DELTA; vert.quadInward = QUADRANT_BR; vertices.push_back(vert);
     427            vert.p.X = v1.X - EDGE_EXPAND_DELTA; vert.p.Y = v1.Y - EDGE_EXPAND_DELTA; vert.quadInward = QUADRANT_TR; vertices.push_back(vert);
    432428            break;
    433429        }
    434430        case TileEdge::RIGHT:
    435431        {
    436             v0 = CFixedVector2D(fixed::FromInt((i+1) * (int)TERRAIN_TILE_SIZE) + r, fixed::FromInt(j * (int)TERRAIN_TILE_SIZE) - r);
    437             v1 = CFixedVector2D(fixed::FromInt((i+1) * (int)TERRAIN_TILE_SIZE) + r, fixed::FromInt((j+1) * (int)TERRAIN_TILE_SIZE) + r);
    438             vert.p.X = v0.X + EDGE_EXPAND_DELTA; vert.p.Y = v0.Y - EDGE_EXPAND_DELTA; vert.quadInward = QUADRANT_TL; vertexes.push_back(vert);
    439             vert.p.X = v1.X + EDGE_EXPAND_DELTA; vert.p.Y = v1.Y + EDGE_EXPAND_DELTA; vert.quadInward = QUADRANT_BL; vertexes.push_back(vert);
     432            const CFixedVector2D v0 (fixed::FromInt((i+1) * (int)TERRAIN_TILE_SIZE) + r, fixed::FromInt(j * (int)TERRAIN_TILE_SIZE) - r);
     433            const CFixedVector2D v1 (fixed::FromInt((i+1) * (int)TERRAIN_TILE_SIZE) + r, fixed::FromInt((j+1) * (int)TERRAIN_TILE_SIZE) + r);
     434            vert.p.X = v0.X + EDGE_EXPAND_DELTA; vert.p.Y = v0.Y - EDGE_EXPAND_DELTA; vert.quadInward = QUADRANT_TL; vertices.push_back(vert);
     435            vert.p.X = v1.X + EDGE_EXPAND_DELTA; vert.p.Y = v1.Y + EDGE_EXPAND_DELTA; vert.quadInward = QUADRANT_BL; vertices.push_back(vert);
    440436            break;
    441437        }
    442438        }
     
    448444        std::vector<EdgeAA>& edgesLeft, std::vector<EdgeAA>& edgesRight,
    449445        std::vector<EdgeAA>& edgesBottom, std::vector<EdgeAA>& edgesTop)
    450446{
    451     edgesLeft.reserve(edgesAA.size());
    452     edgesRight.reserve(edgesAA.size());
    453     edgesBottom.reserve(edgesAA.size());
    454     edgesTop.reserve(edgesAA.size());
     447    const size_t edgeSize = edgesAA.size();
     448    edgesLeft.reserve(edgeSize);
     449    edgesRight.reserve(edgeSize);
     450    edgesBottom.reserve(edgeSize);
     451    edgesTop.reserve(edgeSize);
    455452
    456     for (size_t i = 0; i < edgesAA.size(); ++i)
     453    const std::vector<Edge>::const_iterator itEnd = edgesAA.end();
     454    for (std::vector<Edge>::const_iterator it = edgesAA.begin(); it != itEnd; ++it)
    457455    {
    458         if (a.X <= edgesAA[i].p0.X)
     456        const Edge& edge = *it;
     457        if (a.X <= edge.p0.X)
    459458        {
    460             EdgeAA e = { edgesAA[i].p0, edgesAA[i].p1.Y };
     459            EdgeAA e = { edge.p0, edge.p1.Y };
    461460            edgesLeft.push_back(e);
    462461        }
    463         if (a.X >= edgesAA[i].p1.X)
     462        if (a.X >= edge.p1.X)
    464463        {
    465             EdgeAA e = { edgesAA[i].p1, edgesAA[i].p0.Y };
     464            EdgeAA e = { edge.p1, edge.p0.Y };
    466465            edgesRight.push_back(e);
    467466        }
    468         if (a.Y <= edgesAA[i].p0.Y)
     467        if (a.Y <= edge.p0.Y)
    469468        {
    470             EdgeAA e = { edgesAA[i].p0, edgesAA[i].p1.X };
     469            EdgeAA e = { edge.p0, edge.p1.X };
    471470            edgesBottom.push_back(e);
    472471        }
    473         if (a.Y >= edgesAA[i].p1.Y)
     472        if (a.Y >= edge.p1.Y)
    474473        {
    475             EdgeAA e = { edgesAA[i].p1, edgesAA[i].p0.X };
     474            EdgeAA e = { edge.p1, edge.p0.X };
    476475            edgesTop.push_back(e);
    477476        }
    478477    }
     
    485484{
    486485    CFixedVector2D src;
    487486    EdgeSort(CFixedVector2D src) : src(src) { }
    488     bool operator()(const Edge& a, const Edge& b)
     487    bool operator()(const Edge& a, const Edge& b) const
    489488    {
    490489        if ((a.p0 - src).CompareLength(b.p0 - src) < 0)
    491490            return true;
     
    493492    }
    494493};
    495494
     495// List of collision edges - paths must never cross these.
     496// (Edges are one-sided so intersections are fine in one direction, but not the other direction.)
     497std::vector<Edge> edges;
     498std::vector<Edge> edgesAA; // axis-aligned squares
     499// List of obstruction vertices (plus start/end points); we'll try to find paths through
     500// the graph defined by these vertices
     501std::vector<Vertex> vertices;
     502std::vector<ICmpObstructionManager::ObstructionSquare> squares;
     503
     504std::vector<EdgeAA> edgesLeft;
     505std::vector<EdgeAA> edgesRight;
     506std::vector<EdgeAA> edgesBottom;
     507std::vector<EdgeAA> edgesTop;
     508
    496509void CCmpPathfinder::ComputeShortPath(const IObstructionTestFilter& filter,
    497510    entity_pos_t x0, entity_pos_t z0, entity_pos_t r,
    498511    entity_pos_t range, const Goal& goal, pass_class_t passClass, Path& path)
     
    530543        }
    531544    }
    532545
    533     // List of collision edges - paths must never cross these.
    534     // (Edges are one-sided so intersections are fine in one direction, but not the other direction.)
    535     std::vector<Edge> edges;
    536     std::vector<Edge> edgesAA; // axis-aligned squares
    537546
     547    edges.clear();
     548    edgesAA.clear();
     549    vertices.clear();
     550    squares.clear();
     551
    538552    // Create impassable edges at the max-range boundary, so we can't escape the region
    539553    // where we're meant to be searching
    540     fixed rangeXMin = x0 - range;
    541     fixed rangeXMax = x0 + range;
    542     fixed rangeZMin = z0 - range;
    543     fixed rangeZMax = z0 + range;
     554    const fixed rangeXMin = x0 - range;
     555    const fixed rangeXMax = x0 + range;
     556    const fixed rangeZMin = z0 - range;
     557    const fixed rangeZMax = z0 + range;
    544558    {
    545559        // (The edges are the opposite direction to usual, so it's an inside-out square)
    546560        Edge e0 = { CFixedVector2D(rangeXMin, rangeZMin), CFixedVector2D(rangeXMin, rangeZMax) };
     
    553567        edges.push_back(e3);
    554568    }
    555569
    556     // List of obstruction vertexes (plus start/end points); we'll try to find paths through
    557     // the graph defined by these vertexes
    558     std::vector<Vertex> vertexes;
    559570
    560571    // Add the start point to the graph
    561     CFixedVector2D posStart(x0, z0);
    562     fixed hStart = (posStart - NearestPointOnGoal(posStart, goal)).Length();
    563     Vertex start = { posStart, fixed::Zero(), hStart, 0, Vertex::OPEN, QUADRANT_NONE, QUADRANT_ALL };
    564     vertexes.push_back(start);
     572    const CFixedVector2D posStart(x0, z0);
     573    const fixed hStart = (posStart - NearestPointOnGoal(posStart, goal)).Length();
     574    const Vertex start = { posStart, fixed::Zero(), hStart, 0, Vertex::OPEN, QUADRANT_NONE, QUADRANT_ALL };
     575    vertices.push_back(start);
     576
    565577    const size_t START_VERTEX_ID = 0;
    566578
    567579    // Add the goal vertex to the graph.
    568580    // Since the goal isn't always a point, this a special magic virtual vertex which moves around - whenever
    569581    // we look at it from another vertex, it is moved to be the closest point on the goal shape to that vertex.
    570     Vertex end = { CFixedVector2D(goal.x, goal.z), fixed::Zero(), fixed::Zero(), 0, Vertex::UNEXPLORED, QUADRANT_NONE, QUADRANT_ALL };
    571     vertexes.push_back(end);
     582    {
     583        const Vertex end = { CFixedVector2D(goal.x, goal.z), fixed::Zero(), fixed::Zero(), 0, Vertex::UNEXPLORED, QUADRANT_NONE, QUADRANT_ALL };
     584        vertices.push_back(end);
     585    }
    572586    const size_t GOAL_VERTEX_ID = 1;
    573587
    574588    // Add terrain obstructions
     
    576590        u16 i0, j0, i1, j1;
    577591        NearestTile(rangeXMin, rangeZMin, i0, j0);
    578592        NearestTile(rangeXMax, rangeZMax, i1, j1);
    579         AddTerrainEdges(edgesAA, vertexes, i0, j0, i1, j1, r, passClass, *m_Grid);
     593        AddTerrainEdges(edgesAA, vertices, i0, j0, i1, j1, r, passClass, *m_Grid);
    580594    }
    581595
    582596    // Find all the obstruction squares that might affect us
    583597    CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSimContext(), SYSTEM_ENTITY);
    584     std::vector<ICmpObstructionManager::ObstructionSquare> squares;
    585598    cmpObstructionManager->GetObstructionsInRange(filter, rangeXMin - r, rangeZMin - r, rangeXMax + r, rangeZMax + r, squares);
    586599
    587600    // Resize arrays to reduce reallocations
    588     vertexes.reserve(vertexes.size() + squares.size()*4);
     601    vertices.reserve(vertices.size() + squares.size()*4);
    589602    edgesAA.reserve(edgesAA.size() + squares.size()); // (assume most squares are AA)
    590603
    591     // Convert each obstruction square into collision edges and search graph vertexes
    592     for (size_t i = 0; i < squares.size(); ++i)
     604    // Convert each obstruction square into collision edges and search graph vertices
     605   
     606    Vertex vert;
     607    const std::vector<ICmpObstructionManager::ObstructionSquare>::const_iterator itEnd = squares.end();
     608    for (std::vector<ICmpObstructionManager::ObstructionSquare>::const_iterator it = squares.begin(); it != itEnd; ++it)
    593609    {
    594         CFixedVector2D center(squares[i].x, squares[i].z);
    595         CFixedVector2D u = squares[i].u;
    596         CFixedVector2D v = squares[i].v;
     610        const ICmpObstructionManager::ObstructionSquare& square = *it;
    597611
    598         // Expand the vertexes by the moving unit's collision radius, to find the
     612        const CFixedVector2D center(square.x, square.z);
     613        const CFixedVector2D& u = square.u;
     614        const CFixedVector2D& v = square.v;
     615
     616        // Expand the vertices by the moving unit's collision radius, to find the
    599617        // closest we can get to it
    600618
    601         CFixedVector2D hd0(squares[i].hw + r + EDGE_EXPAND_DELTA, squares[i].hh + r + EDGE_EXPAND_DELTA);
    602         CFixedVector2D hd1(squares[i].hw + r + EDGE_EXPAND_DELTA, -(squares[i].hh + r + EDGE_EXPAND_DELTA));
     619        const CFixedVector2D hd0(square.hw + r + EDGE_EXPAND_DELTA, square.hh + r + EDGE_EXPAND_DELTA);
     620        const CFixedVector2D hd1(square.hw + r + EDGE_EXPAND_DELTA, -(square.hh + r + EDGE_EXPAND_DELTA));
    603621
    604622        // Check whether this is an axis-aligned square
    605         bool aa = (u.X == fixed::FromInt(1) && u.Y == fixed::Zero() && v.X == fixed::Zero() && v.Y == fixed::FromInt(1));
     623        const bool aa = (u.X == fixed::FromInt(1) && u.Y == fixed::Zero() && v.X == fixed::Zero() && v.Y == fixed::FromInt(1));
    606624
    607         Vertex vert;
    608625        vert.status = Vertex::UNEXPLORED;
    609626        vert.quadInward = QUADRANT_NONE;
    610627        vert.quadOutward = QUADRANT_ALL;
    611         vert.p.X = center.X - hd0.Dot(u); vert.p.Y = center.Y + hd0.Dot(v); if (aa) vert.quadInward = QUADRANT_BR; vertexes.push_back(vert);
    612         vert.p.X = center.X - hd1.Dot(u); vert.p.Y = center.Y + hd1.Dot(v); if (aa) vert.quadInward = QUADRANT_TR; vertexes.push_back(vert);
    613         vert.p.X = center.X + hd0.Dot(u); vert.p.Y = center.Y - hd0.Dot(v); if (aa) vert.quadInward = QUADRANT_TL; vertexes.push_back(vert);
    614         vert.p.X = center.X + hd1.Dot(u); vert.p.Y = center.Y - hd1.Dot(v); if (aa) vert.quadInward = QUADRANT_BL; vertexes.push_back(vert);
     628        vert.p.X = center.X - hd0.Dot(u); vert.p.Y = center.Y + hd0.Dot(v); if (aa) vert.quadInward = QUADRANT_BR; vertices.push_back(vert);
     629        vert.p.X = center.X - hd1.Dot(u); vert.p.Y = center.Y + hd1.Dot(v); if (aa) vert.quadInward = QUADRANT_TR; vertices.push_back(vert);
     630        vert.p.X = center.X + hd0.Dot(u); vert.p.Y = center.Y - hd0.Dot(v); if (aa) vert.quadInward = QUADRANT_TL; vertices.push_back(vert);
     631        vert.p.X = center.X + hd1.Dot(u); vert.p.Y = center.Y - hd1.Dot(v); if (aa) vert.quadInward = QUADRANT_BL; vertices.push_back(vert);
    615632
    616633        // Add the edges:
    617634
    618         CFixedVector2D h0(squares[i].hw + r, squares[i].hh + r);
    619         CFixedVector2D h1(squares[i].hw + r, -(squares[i].hh + r));
     635        const CFixedVector2D h1(square.hw + r, -(square.hh + r));
     636       
     637        const fixed h1DotU(h1.Dot(u));
     638        const fixed h1DotV(h1.Dot(v));
    620639
    621         CFixedVector2D ev0(center.X - h0.Dot(u), center.Y + h0.Dot(v));
    622         CFixedVector2D ev1(center.X - h1.Dot(u), center.Y + h1.Dot(v));
    623         CFixedVector2D ev2(center.X + h0.Dot(u), center.Y - h0.Dot(v));
    624         CFixedVector2D ev3(center.X + h1.Dot(u), center.Y - h1.Dot(v));
     640        const CFixedVector2D ev1(center.X - h1DotU, center.Y + h1DotV);
     641        const CFixedVector2D ev3(center.X + h1DotU, center.Y - h1DotV);
    625642        if (aa)
    626643        {
    627644            Edge e = { ev1, ev3 };
     
    629646        }
    630647        else
    631648        {
     649            const CFixedVector2D h0(square.hw + r, square.hh + r);
     650
     651            const fixed h0DotU(h0.Dot(u));
     652            const fixed h0DotV(h0.Dot(v));
     653
     654            const CFixedVector2D ev0(center.X - h0DotU, center.Y + h0DotV);
     655            const CFixedVector2D ev2(center.X + h0DotU, center.Y - h0DotV);
     656
    632657            Edge e0 = { ev0, ev1 };
    633658            Edge e1 = { ev1, ev2 };
    634659            Edge e2 = { ev2, ev3 };
    635660            Edge e3 = { ev3, ev0 };
     661
    636662            edges.push_back(e0);
    637663            edges.push_back(e1);
    638664            edges.push_back(e2);
    639665            edges.push_back(e3);
    640666        }
    641667
    642         // TODO: should clip out vertexes and edges that are outside the range,
     668        // TODO: should clip out vertices and edges that are outside the range,
    643669        // to reduce the search space
    644670    }
    645671
    646     ENSURE(vertexes.size() < 65536); // we store array indexes as u16
     672    ENSURE(vertices.size() < 65536); // we store array indexes as u16
    647673
    648674    if (m_DebugOverlay)
    649675    {
     
    684710    // Since we are just measuring Euclidean distance the heuristic is admissible,
    685711    // so we never have to re-examine a node once it's been moved to the closed set.
    686712
    687     // To save time in common cases, we don't precompute a graph of valid edges between vertexes;
     713    // To save time in common cases, we don't precompute a graph of valid edges between vertices;
    688714    // we do it lazily instead. When the search algorithm reaches a vertex, we examine every other
    689715    // vertex and see if we can reach it without hitting any collision edges, and ignore the ones
    690716    // we can't reach. Since the algorithm can only reach a vertex once (and then it'll be marked
     
    703729    {
    704730        // Move best tile from open to closed
    705731        PriorityQueue::Item curr = open.pop();
    706         vertexes[curr.id].status = Vertex::CLOSED;
     732        vertices[curr.id].status = Vertex::CLOSED;
    707733
    708734        // If we've reached the destination, stop
    709735        if (curr.id == GOAL_VERTEX_ID)
     
    712738            break;
    713739        }
    714740
     741        const Vertex &VertexCurr = vertices[curr.id];
     742        const CFixedVector2D& vertexPosition = VertexCurr.p;
     743       
    715744        // Sort the edges so ones nearer this vertex are checked first by CheckVisibility,
    716745        // since they're more likely to block the rays
    717         std::sort(edgesAA.begin(), edgesAA.end(), EdgeSort(vertexes[curr.id].p));
     746        std::sort(edgesAA.begin(), edgesAA.end(), EdgeSort(VertexCurr.p));
    718747
    719         std::vector<EdgeAA> edgesLeft;
    720         std::vector<EdgeAA> edgesRight;
    721         std::vector<EdgeAA> edgesBottom;
    722         std::vector<EdgeAA> edgesTop;
    723         SplitAAEdges(vertexes[curr.id].p, edgesAA, edgesLeft, edgesRight, edgesBottom, edgesTop);
     748        edgesLeft.clear();
     749        edgesRight.clear();
     750        edgesBottom.clear();
     751        edgesTop.clear();
     752        SplitAAEdges(VertexCurr.p, edgesAA, edgesLeft, edgesRight, edgesBottom, edgesTop);
    724753
    725754        // Check the lines to every other vertex
    726         for (size_t n = 0; n < vertexes.size(); ++n)
     755        size_t n = 0;
     756        const std::vector<Vertex>::iterator itVEnd = vertices.end();
     757        for (std::vector<Vertex>::iterator itv = vertices.begin(); itv != itVEnd; ++itv, n++)
    727758        {
    728             if (vertexes[n].status == Vertex::CLOSED)
     759            Vertex& vertexN = *itv;
     760            if (vertexN.status == Vertex::CLOSED)
    729761                continue;
    730762
    731763            // If this is the magical goal vertex, move it to near the current vertex
    732764            CFixedVector2D npos;
    733765            if (n == GOAL_VERTEX_ID)
    734766            {
    735                 npos = NearestPointOnGoal(vertexes[curr.id].p, goal);
     767                npos = NearestPointOnGoal(vertexPosition, goal);
    736768
    737                 // To prevent integer overflows later on, we need to ensure all vertexes are
     769                // To prevent integer overflows later on, we need to ensure all vertices are
    738770                // 'close' to the source. The goal might be far away (not a good idea but
    739771                // sometimes it happens), so clamp it to the current search range
    740772                npos.X = clamp(npos.X, rangeXMin, rangeXMax);
     
    742774            }
    743775            else
    744776            {
    745                 npos = vertexes[n].p;
     777                npos = vertexN.p;
    746778            }
    747779
    748780            // Work out which quadrant(s) we're approaching the new vertex from
    749             u8 quad = 0;
    750             if (vertexes[curr.id].p.X <= npos.X && vertexes[curr.id].p.Y <= npos.Y) quad |= QUADRANT_BL;
    751             if (vertexes[curr.id].p.X >= npos.X && vertexes[curr.id].p.Y >= npos.Y) quad |= QUADRANT_TR;
    752             if (vertexes[curr.id].p.X <= npos.X && vertexes[curr.id].p.Y >= npos.Y) quad |= QUADRANT_TL;
    753             if (vertexes[curr.id].p.X >= npos.X && vertexes[curr.id].p.Y <= npos.Y) quad |= QUADRANT_BR;
     781            u8 quad = 0;   
    754782
     783            if (vertexPosition.X <= npos.X && vertexPosition.Y <= npos.Y) quad |= QUADRANT_BL;
     784            if (vertexPosition.X >= npos.X && vertexPosition.Y >= npos.Y) quad |= QUADRANT_TR;
     785            if (vertexPosition.X <= npos.X && vertexPosition.Y >= npos.Y) quad |= QUADRANT_TL;
     786            if (vertexPosition.X >= npos.X && vertexPosition.Y <= npos.Y) quad |= QUADRANT_BR;
     787
    755788            // Check that the new vertex is in the right quadrant for the old vertex
    756             if (!(vertexes[curr.id].quadOutward & quad))
     789            if (!(VertexCurr.quadOutward & quad))
    757790            {
    758791                // Hack: Always head towards the goal if possible, to avoid missing it if it's
    759792                // inside another unit
     
    763796                }
    764797            }
    765798
    766             bool visible =
    767                 CheckVisibilityLeft(vertexes[curr.id].p, npos, edgesLeft) &&
    768                 CheckVisibilityRight(vertexes[curr.id].p, npos, edgesRight) &&
    769                 CheckVisibilityBottom(vertexes[curr.id].p, npos, edgesBottom) &&
    770                 CheckVisibilityTop(vertexes[curr.id].p, npos, edgesTop) &&
    771                 CheckVisibility(vertexes[curr.id].p, npos, edges);
     799            const CFixedVector2D abn ((npos - vertexPosition).Perpendicular());
     800            bool visible = CheckVisibilityLeft(vertexPosition, npos, abn, edgesLeft) &&
     801                CheckVisibilityRight(vertexPosition, npos, abn,  edgesRight) &&
     802                CheckVisibilityBottom(vertexPosition, npos, abn,  edgesBottom) &&
     803                CheckVisibilityTop(vertexPosition, npos, abn,  edgesTop) &&
     804                CheckVisibility(vertexPosition, npos, abn,  edges);
     805           
     806           
    772807
    773808            /*
    774809            // Render the edges that we examine
    775810            m_DebugOverlayShortPathLines.push_back(SOverlayLine());
    776811            m_DebugOverlayShortPathLines.back().m_Color = visible ? CColor(0, 1, 0, 0.5) : CColor(1, 0, 0, 0.5);
    777812            std::vector<float> xz;
    778             xz.push_back(vertexes[curr.id].p.X.ToFloat());
    779             xz.push_back(vertexes[curr.id].p.Y.ToFloat());
     813            xz.push_back(VertexCurr.p.X.ToFloat());
     814            xz.push_back(VertexCurr.p.Y.ToFloat());
    780815            xz.push_back(npos.X.ToFloat());
    781816            xz.push_back(npos.Y.ToFloat());
    782817            SimRender::ConstructLineOnGround(GetSimContext(), xz, m_DebugOverlayShortPathLines.back(), false);
     
    784819
    785820            if (visible)
    786821            {
    787                 fixed g = vertexes[curr.id].g + (vertexes[curr.id].p - npos).Length();
     822                const fixed g = VertexCurr.g + (vertexPosition - npos).Length();
    788823
    789824                // If this is a new tile, compute the heuristic distance
    790                 if (vertexes[n].status == Vertex::UNEXPLORED)
     825                if (vertexN.status == Vertex::UNEXPLORED)
    791826                {
    792827                    // Add it to the open list:
    793                     vertexes[n].status = Vertex::OPEN;
    794                     vertexes[n].g = g;
    795                     vertexes[n].h = DistanceToGoal(npos, goal);
    796                     vertexes[n].pred = curr.id;
     828                    vertexN.status = Vertex::OPEN;
     829                    vertexN.g = g;
     830                    vertexN.h = DistanceToGoal(npos, goal);
     831                    vertexN.pred = curr.id;
    797832
    798833                    // If this is an axis-aligned shape, the path must continue in the same quadrant
    799834                    // direction (but not go into the inside of the shape).
    800835                    // Hack: If we started *inside* a shape then perhaps headed to its corner (e.g. the unit
    801836                    // was very near another unit), don't restrict further pathing.
    802                     if (vertexes[n].quadInward && !(curr.id == START_VERTEX_ID && g < fixed::FromInt(8)))
    803                         vertexes[n].quadOutward = ((~vertexes[n].quadInward) & quad) & 0xF;
     837                    if (vertexN.quadInward && !(curr.id == START_VERTEX_ID && g < fixed::FromInt(8)))
     838                        vertexN.quadOutward = ((~vertexN.quadInward) & quad) & 0xF;
    804839
    805840                    if (n == GOAL_VERTEX_ID)
    806                         vertexes[n].p = npos; // remember the new best goal position
     841                        vertexN.p = npos; // remember the new best goal position
    807842
    808                     PriorityQueue::Item t = { (u16)n, g + vertexes[n].h };
     843                    PriorityQueue::Item t = { (u16)n, g + vertexN.h };
    809844                    open.push(t);
    810845
    811846                    // Remember the heuristically best vertex we've seen so far, in case we never actually reach the target
    812                     if (vertexes[n].h < hBest)
     847                    if (vertexN.h < hBest)
    813848                    {
    814849                        idBest = (u16)n;
    815                         hBest = vertexes[n].h;
     850                        hBest = vertexN.h;
    816851                    }
    817852                }
    818853                else // must be OPEN
    819854                {
    820855                    // If we've already seen this tile, and the new path to this tile does not have a
    821856                    // better cost, then stop now
    822                     if (g >= vertexes[n].g)
     857                    if (g >= vertexN.g)
    823858                        continue;
    824859
    825860                    // Otherwise, we have a better path, so replace the old one with the new cost/parent
    826                     vertexes[n].g = g;
    827                     vertexes[n].pred = curr.id;
     861                    vertexN.g = g;
     862                    vertexN.pred = curr.id;
    828863
    829864                    // If this is an axis-aligned shape, the path must continue in the same quadrant
    830865                    // direction (but not go into the inside of the shape).
    831                     if (vertexes[n].quadInward)
    832                         vertexes[n].quadOutward = ((~vertexes[n].quadInward) & quad) & 0xF;
     866                    if (vertexN.quadInward)
     867                        vertexN.quadOutward = ((~vertexN.quadInward) & quad) & 0xF;
    833868
    834869                    if (n == GOAL_VERTEX_ID)
    835                         vertexes[n].p = npos; // remember the new best goal position
     870                        vertexN.p = npos; // remember the new best goal position
    836871
    837                     open.promote((u16)n, g + vertexes[n].h);
     872                    open.promote((u16)n, g + vertexN.h);
    838873                }
    839874            }
    840875        }
    841876    }
    842877
    843878    // Reconstruct the path (in reverse)
    844     for (u16 id = idBest; id != START_VERTEX_ID; id = vertexes[id].pred)
     879    for (u16 id = idBest; id != START_VERTEX_ID; id = vertices[id].pred)
    845880    {
    846         Waypoint w = { vertexes[id].p.X, vertexes[id].p.Y };
     881        Waypoint w = { vertices[id].p.X, vertices[id].p.Y };
    847882        path.m_Waypoints.push_back(w);
    848883    }
    849884
     
    867902
    868903    UpdateGrid();
    869904
    870     std::vector<Edge> edgesAA;
    871     std::vector<Vertex> vertexes;
     905    edgesAA.clear();
     906    vertices.clear();
    872907
    873908    u16 i0, j0, i1, j1;
    874909    NearestTile(std::min(x0, x1) - r, std::min(z0, z1) - r, i0, j0);
    875910    NearestTile(std::max(x0, x1) + r, std::max(z0, z1) + r, i1, j1);
    876     AddTerrainEdges(edgesAA, vertexes, i0, j0, i1, j1, r, passClass, *m_Grid);
     911    AddTerrainEdges(edgesAA, vertices, i0, j0, i1, j1, r, passClass, *m_Grid);
    877912
    878913    CFixedVector2D a(x0, z0);
    879914    CFixedVector2D b(x1, z1);
    880915
    881     std::vector<EdgeAA> edgesLeft;
    882     std::vector<EdgeAA> edgesRight;
    883     std::vector<EdgeAA> edgesBottom;
    884     std::vector<EdgeAA> edgesTop;
     916    edgesLeft.clear();
     917    edgesRight.clear();
     918    edgesBottom.clear();
     919    edgesTop.clear();
    885920    SplitAAEdges(a, edgesAA, edgesLeft, edgesRight, edgesBottom, edgesTop);
    886921
     922
     923    const CFixedVector2D abn ((b - a).Perpendicular());
    887924    bool visible =
    888         CheckVisibilityLeft(a, b, edgesLeft) &&
    889         CheckVisibilityRight(a, b, edgesRight) &&
    890         CheckVisibilityBottom(a, b, edgesBottom) &&
    891         CheckVisibilityTop(a, b, edgesTop);
     925        CheckVisibilityLeft(a, b, abn, edgesLeft) &&
     926        CheckVisibilityRight(a, b, abn,  edgesRight) &&
     927        CheckVisibilityBottom(a, b, abn, edgesBottom) &&
     928        CheckVisibilityTop(a, b, abn,  edgesTop);
    892929
     930
     931
     932
     933
    893934    return visible;
    894935}
  • source/simulation2/components/CCmpPathfinder.cpp

     
    238238}
    239239
    240240
    241 fixed CCmpPathfinder::GetMovementSpeed(entity_pos_t x0, entity_pos_t z0, u8 costClass)
     241fixed CCmpPathfinder::GetMovementSpeed(const entity_pos_t x0, const entity_pos_t z0, u8 costClass)
    242242{
    243243    UpdateGrid();
    244244
     
    275275    return m_UnitCostClassTags[name];
    276276}
    277277
    278 fixed CCmpPathfinder::DistanceToGoal(CFixedVector2D pos, const CCmpPathfinder::Goal& goal)
     278fixed CCmpPathfinder::DistanceToGoal( const CFixedVector2D& pos, const CCmpPathfinder::Goal& goal)
    279279{
    280280    switch (goal.type)
    281281    {
  • source/simulation2/components/CCmpPathfinder_Tile.cpp

     
    2020 * Tile-based algorithm for CCmpPathfinder.
    2121 * This is a fairly naive algorithm and could probably be improved substantially
    2222 * (hopefully without needing to change the interface much).
     23 * TODO:
     24 ** use squared length for all distance comparisons, saves a sqrt per comparison: huge speed up
     25 ** use pointers for edge so that memory movement are smaller, prealloc edge using memory pools so that data is contiguous: huge speed up
    2326 */
    2427
    2528#include "precompiled.h"
     
    5356        STATUS_CLOSED = 2
    5457    };
    5558
    56     bool IsUnexplored() { return status == STATUS_UNEXPLORED; }
    57     bool IsOpen() { return status == STATUS_OPEN; }
    58     bool IsClosed() { return status == STATUS_CLOSED; }
     59    bool IsUnexplored() const{ return status == STATUS_UNEXPLORED; }
     60    bool IsOpen()const { return status == STATUS_OPEN; }
     61    bool IsClosed()const { return status == STATUS_CLOSED; }
    5962    void SetStatusOpen() { status = STATUS_OPEN; }
    6063    void SetStatusClosed() { status = STATUS_CLOSED; }
    6164
    6265    // Get pi,pj coords of predecessor to this tile on best path, given i,j coords of this tile
    63     u16 GetPredI(u16 i) { return (u16)(i + dpi); }
    64     u16 GetPredJ(u16 j) { return (u16)(j + dpj); }
     66    u16 GetPredI(const u16 i) const { return (u16)(i + dpi); }
     67    u16 GetPredJ(const u16 j) const { return (u16)(j + dpj); }
    6568    // Set the pi,pj coords of predecessor, given i,j coords of this tile
    6669    void SetPred(u16 pi_, u16 pj_, u16 i, u16 j)
    6770    {
     
    8285    u32 h; // h (heuristic cost to goal) (TODO: is it really better for performance to store this instead of recomputing?)
    8386
    8487#if PATHFIND_DEBUG
    85     u32 GetStep() { return step; }
    86     void SetStep(u32 s) { step = s; }
     88    u32 GetStep() const{ return step; }
     89    void SetStep(const u32 s) { step = s; }
    8790private:
    8891    u32 step; // step at which this tile was last processed (for debug rendering)
    8992#else
    90     u32 GetStep() { return 0; }
    91     void SetStep(u32) { }
     93    u32 GetStep()const { return 0; }
     94    void SetStep(const u32) { }
    9295#endif
    9396
    9497};
     
    113116        m_Pathfinder.UpdateGrid();
    114117    }
    115118
    116     virtual void ProcessTile(ssize_t i, ssize_t j)
     119    virtual void ProcessTile(const ssize_t i, const ssize_t j)
    117120    {
    118121        if (m_Pathfinder.m_Grid && !IS_PASSABLE(m_Pathfinder.m_Grid->get((int)i, (int)j), m_Pathfinder.m_DebugPassClass))
    119122            RenderTile(CColor(1, 0, 0, 0.6f), false);
     
    215218#endif
    216219};
    217220
    218 static bool AtGoal(u16 i, u16 j, const ICmpPathfinder::Goal& goal)
     221static bool AtGoal(const u16 i, const u16 j, const ICmpPathfinder::Goal& goal)
    219222{
    220223    // Allow tiles slightly more than sqrt(2) from the actual goal,
    221224    // i.e. adjacent diagonally to the target tile
    222     fixed tolerance = entity_pos_t::FromInt(TERRAIN_TILE_SIZE*3/2);
     225    const fixed tolerance = entity_pos_t::FromInt(TERRAIN_TILE_SIZE*3/2);
    223226
    224227    entity_pos_t x, z;
    225228    CCmpPathfinder::TileCenter(i, j, x, z);
    226     fixed dist = CCmpPathfinder::DistanceToGoal(CFixedVector2D(x, z), goal);
     229    const fixed dist = CCmpPathfinder::DistanceToGoal(CFixedVector2D(x, z), goal);
    227230    return (dist < tolerance);
    228231}
    229232
    230233// Calculate heuristic cost from tile i,j to destination
    231234// (This ought to be an underestimate for correctness)
    232 static u32 CalculateHeuristic(u16 i, u16 j, u16 iGoal, u16 jGoal, u16 rGoal)
     235static u32 CalculateHeuristic(const u16 i, const u16 j, const u16 iGoal, const u16 jGoal, const u16 rGoal)
    233236{
    234237#if USE_DIAGONAL_MOVEMENT
    235     CFixedVector2D pos (fixed::FromInt(i), fixed::FromInt(j));
    236     CFixedVector2D goal (fixed::FromInt(iGoal), fixed::FromInt(jGoal));
    237     fixed dist = (pos - goal).Length();
     238    const CFixedVector2D pos (fixed::FromInt(i), fixed::FromInt(j));
     239    const CFixedVector2D goal (fixed::FromInt(iGoal), fixed::FromInt(jGoal));
     240    const fixed dist = pos.computeDistanceLength(goal);
    238241    // TODO: the heuristic could match the costs better - it's not really Euclidean movement
    239242
    240243    fixed rdist = dist - fixed::FromInt(rGoal);
     
    255258}
    256259
    257260// Calculate movement cost from predecessor tile pi,pj to tile i,j
    258 static u32 CalculateCostDelta(u16 pi, u16 pj, u16 i, u16 j, PathfindTileGrid* tempGrid, u32 tileCost)
     261static u32 CalculateCostDelta(const u16 pi, const u16 pj, const PathfindTile &p,
     262                                const u16 i, const u16 j,
     263                                PathfindTileGrid* const tempGrid,
     264                                const u32 tileCost)
    259265{
    260266    u32 dg = tileCost;
    261267
     
    269275    // likely to be reasonably stable) and reducing the cost, and use a Euclidean heuristic.
    270276    // At least this makes paths look a bit nicer for now...
    271277
    272     PathfindTile& p = tempGrid->get(pi, pj);
    273     u16 ppi = p.GetPredI(pi);
    274     u16 ppj = p.GetPredJ(pj);
     278    //PathfindTile& p = tempGrid->get(pi, pj);
     279    const u16 ppi = p.GetPredI(pi);
     280    const u16 ppj = p.GetPredJ(pj);
    275281    if (ppi != i && ppj != j)
     282    {
    276283        dg = (dg << 16) / 92682; // dg*sqrt(2)/2
     284    }
    277285    else
    278286    {
    279         PathfindTile& pp = tempGrid->get(ppi, ppj);
    280         int di = abs(i - pp.GetPredI(ppi));
    281         int dj = abs(j - pp.GetPredJ(ppj));
     287        const PathfindTile& pp = tempGrid->get(ppi, ppj);
     288        const int di = abs(i - pp.GetPredI(ppi));
     289        const int dj = abs(j - pp.GetPredJ(ppj));
    282290        if ((di == 1 && dj == 2) || (di == 2 && dj == 1))
    283291            dg = (dg << 16) / 79742; // dg*(sqrt(5)-sqrt(2))
    284292    }
     
    288296}
    289297
    290298// Do the A* processing for a neighbour tile i,j.
    291 static void ProcessNeighbour(u16 pi, u16 pj, u16 i, u16 j, u32 pg, PathfinderState& state)
     299static void ProcessNeighbour(const u16 pi, const u16 pj, const PathfindTile &pTile,
     300                             const u16 i,  const u16 j,  const u32 pg,
     301                             PathfinderState& state)
    292302{
    293303#if PATHFIND_STATS
    294304    state.numProcessed++;
    295305#endif
    296306
    297307    // Reject impassable tiles
    298     TerrainTile tileTag = state.terrain->get(i, j);
     308    const TerrainTile tileTag = state.terrain->get(i, j);
    299309    if (!IS_PASSABLE(tileTag, state.passClass) && !state.ignoreImpassable)
    300310        return;
    301311
    302     u32 dg = CalculateCostDelta(pi, pj, i, j, state.tiles, state.moveCosts.at(GET_COST_CLASS(tileTag)));
     312    const u32 dg = CalculateCostDelta(pi, pj, pTile, i, j, state.tiles, state.moveCosts.at(GET_COST_CLASS(tileTag)));
    303313
    304     u32 g = pg + dg; // cost to this tile = cost to predecessor + delta from predecessor
     314    const u32 g = pg + dg; // cost to this tile = cost to predecessor + delta from predecessor
    305315
    306316    PathfindTile& n = state.tiles->get(i, j);
    307317
     
    363373#endif
    364374}
    365375
    366 void CCmpPathfinder::ComputePath(entity_pos_t x0, entity_pos_t z0, const Goal& goal, pass_class_t passClass, cost_class_t costClass, Path& path)
     376void CCmpPathfinder::ComputePath(const entity_pos_t x0, const entity_pos_t z0, const Goal& goal, const pass_class_t passClass, const cost_class_t costClass, Path& path)
    367377{
    368378    UpdateGrid();
    369379
     
    384394        return;
    385395    }
    386396
     397
    387398    // If the target is a circle, we want to aim for the edge of it (so e.g. if we're inside
    388399    // a large circle then the heuristics will aim us directly outwards);
    389400    // otherwise just aim at the center point. (We'll never try moving outwards to a square shape.)
     
    397408
    398409    state.steps = 0;
    399410
    400     state.tiles = new PathfindTileGrid(m_MapSize, m_MapSize);
     411    if (m_DebugGrid)
     412    {
     413        state.tiles = m_DebugGrid;
     414        state.tiles->reset();
     415    }
     416    else
     417    {
     418        state.tiles = new PathfindTileGrid(m_MapSize, m_MapSize);
     419    }
    401420    state.terrain = m_Grid;
    402421
    403422    state.iBest = i0;
     
    433452
    434453        // Move best tile from open to closed
    435454        PriorityQueue::Item curr = state.open.pop();
    436         u16 i = curr.id.first;
    437         u16 j = curr.id.second;
    438         state.tiles->get(i, j).SetStatusClosed();
     455        const u16 i = curr.id.first;
     456        const u16 j = curr.id.second;
     457        PathfindTile &pTile = state.tiles->get(i, j);
     458        pTile.SetStatusClosed();
    439459
    440460        // If we've reached the destination, stop
    441461        if (AtGoal(i, j, goal))
     
    450470        // take it and forbid any further use of impassable tiles
    451471        if (state.ignoreImpassable)
    452472        {
    453             if (i > 0 && IS_PASSABLE(state.terrain->get(i-1, j), state.passClass))
     473            if (i != 0 && IS_PASSABLE(state.terrain->get(i-1, j), state.passClass))
    454474                state.ignoreImpassable = false;
    455475            else if (i < m_MapSize-1 && IS_PASSABLE(state.terrain->get(i+1, j), state.passClass))
    456476                state.ignoreImpassable = false;
    457             else if (j > 0 && IS_PASSABLE(state.terrain->get(i, j-1), state.passClass))
     477            else if (j != 0 && IS_PASSABLE(state.terrain->get(i, j-1), state.passClass))
    458478                state.ignoreImpassable = false;
    459479            else if (j < m_MapSize-1 && IS_PASSABLE(state.terrain->get(i, j+1), state.passClass))
    460480                state.ignoreImpassable = false;
    461481        }
    462482
    463         u32 g = state.tiles->get(i, j).cost;
    464         if (i > 0)
    465             ProcessNeighbour(i, j, (u16)(i-1), j, g, state);
     483        const u32 g = pTile.cost;
     484        if (i != 0)
     485            ProcessNeighbour(i, j, pTile, (u16)(i-1), j, g, state);
    466486        if (i < m_MapSize-1)
    467             ProcessNeighbour(i, j, (u16)(i+1), j, g, state);
    468         if (j > 0)
    469             ProcessNeighbour(i, j, i, (u16)(j-1), g, state);
     487            ProcessNeighbour(i, j, pTile, (u16)(i+1), j, g, state);
     488        if (j != 0)
     489            ProcessNeighbour(i, j, pTile, i, (u16)(j-1), g, state);
    470490        if (j < m_MapSize-1)
    471             ProcessNeighbour(i, j, i, (u16)(j+1), g, state);
     491            ProcessNeighbour(i, j, pTile, i, (u16)(j+1), g, state);
    472492    }
    473493
    474494    // Reconstruct the path (in reverse)
     
    487507    }
    488508
    489509    // Save this grid for debug display
    490     delete m_DebugGrid;
    491510    m_DebugGrid = state.tiles;
    492511    m_DebugSteps = state.steps;
    493512
  • source/simulation2/components/CCmpTerritoryManager.cpp

     
    5656
    5757    TerritoryOverlay(CCmpTerritoryManager& manager);
    5858    virtual void StartRender();
    59     virtual void ProcessTile(ssize_t i, ssize_t j);
     59    virtual void ProcessTile(const ssize_t i, const ssize_t j);
    6060};
    6161
    6262class CCmpTerritoryManager : public ICmpTerritoryManager
     
    279279
    280280typedef PriorityQueueHeap<std::pair<u16, u16>, u32, std::greater<u32> > OpenQueue;
    281281
    282 static void ProcessNeighbour(u32 falloff, u16 i, u16 j, u32 pg, bool diagonal,
     282static void ProcessNeighbour(const u32 falloff, const u16 i, const u16 j, const u32 pg, bool diagonal,
    283283        Grid<u32>& grid, OpenQueue& queue, const Grid<u8>& costGrid)
    284284{
    285285    u32 dg = falloff * costGrid.get(i, j);
     
    291291    if (pg <= grid.get(i, j) + dg)
    292292        return;
    293293
    294     u32 g = pg - dg; // cost to this tile = cost to predecessor - falloff from predecessor
     294    const u32 g = pg - dg; // cost to this tile = cost to predecessor - falloff from predecessor
    295295
    296296    grid.set(i, j, g);
    297297    OpenQueue::Item tile = { std::make_pair(i, j), g };
    298298    queue.push(tile);
    299299}
    300300
    301 static void FloodFill(Grid<u32>& grid, Grid<u8>& costGrid, OpenQueue& openTiles, u32 falloff)
     301static void FloodFill(Grid<u32>& grid, Grid<u8>& costGrid, OpenQueue& openTiles, const u32 falloff)
    302302{
    303303    u16 tilesW = grid.m_W;
    304304    u16 tilesH = grid.m_H;
     
    308308        OpenQueue::Item tile = openTiles.pop();
    309309
    310310        // Process neighbours (if they're not off the edge of the map)
    311         u16 x = tile.id.first;
    312         u16 z = tile.id.second;
     311        const u16 x = tile.id.first;
     312        const u16 z = tile.id.second;
    313313        if (x > 0)
    314314            ProcessNeighbour(falloff, (u16)(x-1), z, tile.rank, false, grid, openTiles, costGrid);
    315315        if (x < tilesW-1)
     
    343343    if (!cmpTerrain->IsLoaded())
    344344        return;
    345345
    346     u16 tilesW = cmpTerrain->GetTilesPerSide();
    347     u16 tilesH = cmpTerrain->GetTilesPerSide();
     346    const u16 tilesW = cmpTerrain->GetTilesPerSide();
     347    const u16 tilesH = cmpTerrain->GetTilesPerSide();
    348348
    349349    m_Territories = new Grid<u8>(tilesW, tilesH);
    350350
     
    352352    Grid<u8> influenceGrid(tilesW, tilesH);
    353353
    354354    CmpPtr<ICmpPathfinder> cmpPathfinder(GetSimContext(), SYSTEM_ENTITY);
    355     ICmpPathfinder::pass_class_t passClassDefault = cmpPathfinder->GetPassabilityClass("default");
    356     ICmpPathfinder::pass_class_t passClassUnrestricted = cmpPathfinder->GetPassabilityClass("unrestricted");
     355    const ICmpPathfinder::pass_class_t passClassDefault = cmpPathfinder->GetPassabilityClass("default");
     356    const ICmpPathfinder::pass_class_t passClassUnrestricted = cmpPathfinder->GetPassabilityClass("unrestricted");
    357357
    358358    const Grid<u16>& passGrid = cmpPathfinder->GetPassabilityGrid();
    359359    for (u16 j = 0; j < tilesH; ++j)
    360360    {
    361361        for (u16 i = 0; i < tilesW; ++i)
    362362        {
    363             u16 g = passGrid.get(i, j);
     363            const u16 g = passGrid.get(i, j);
    364364            u8 cost;
    365365            if (g & passClassUnrestricted)
    366366                cost = 255; // off the world; use maximum cost
     
    416416    std::vector<std::pair<player_id_t, Grid<u32> > > playerGrids;
    417417    // TODO: this is a large waste of memory; we don't really need to store
    418418    // all the intermediate grids
    419 
    420     for (std::map<player_id_t, std::vector<entity_id_t> >::iterator it = influenceEntities.begin(); it != influenceEntities.end(); ++it)
     419   
     420    Grid<u32> entityTempGrid(tilesW, tilesH);
     421    for (std::map<player_id_t, std::vector<entity_id_t> >::iterator it = influenceEntities.begin();
     422        it != influenceEntities.end(); ++it)
    421423    {
    422424        Grid<u32> playerGrid(tilesW, tilesH);
    423425
    424426        std::vector<entity_id_t>& ents = it->second;
    425         for (std::vector<entity_id_t>::iterator eit = ents.begin(); eit != ents.end(); ++eit)
     427        std::vector<entity_id_t>::iterator entEnd = ents.end();
     428        for (std::vector<entity_id_t>::iterator eit = ents.begin(); eit != entEnd; ++eit)
    426429        {
    427430            // Compute the influence map of the current entity, then add it to the player grid
     431            entityTempGrid.reset();
    428432
    429             Grid<u32> entityGrid(tilesW, tilesH);
    430 
    431433            CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), *eit);
    432434            CFixedVector2D pos = cmpPosition->GetPosition2D();
    433435            u16 i = (u16)clamp((pos.X / (int)TERRAIN_TILE_SIZE).ToInt_RoundToNegInfinity(), 0, tilesW-1);
     
    442444            // when doing all the sums
    443445
    444446            // Initialise the tile under the entity
    445             entityGrid.set(i, j, weight);
     447            entityTempGrid.set(i, j, weight);
    446448            OpenQueue openTiles;
    447449            OpenQueue::Item tile = { std::make_pair((u16)i, (i16)j), weight };
    448450            openTiles.push(tile);
    449451
    450452            // Expand influences outwards
    451             FloodFill(entityGrid, influenceGrid, openTiles, falloff);
     453            FloodFill(entityTempGrid, influenceGrid, openTiles, falloff);
    452454
    453455            // TODO: we should do a sparse grid and only add the non-zero regions, for performance
    454             for (u16 j = 0; j < entityGrid.m_H; ++j)
    455                 for (u16 i = 0; i < entityGrid.m_W; ++i)
    456                     playerGrid.set(i, j, playerGrid.get(i, j) + entityGrid.get(i, j));
     456            for (u16 j = 0; j < tilesH; ++j)
     457            {
     458                for (u16 i = 0; i < tilesW; ++i)
     459                {
     460                    playerGrid.add(i, j, entityTempGrid.get(i, j));
     461                }
     462            }
    457463        }
    458464
    459465        playerGrids.push_back(std::make_pair(it->first, playerGrid));
    460466    }
    461467
    462468    // Set m_Territories to the player ID with the highest influence for each tile
     469    const size_t playerGridsSize = playerGrids.size();
    463470    for (u16 j = 0; j < tilesH; ++j)
    464471    {
    465472        for (u16 i = 0; i < tilesW; ++i)
    466473        {
    467474            u32 bestWeight = 0;
    468             for (size_t k = 0; k < playerGrids.size(); ++k)
     475            for (size_t k = 0; k < playerGridsSize; ++k)
    469476            {
    470477                u32 w = playerGrids[k].second.get(i, j);
    471478                if (w > bestWeight)
     
    480487
    481488    // Detect territories connected to a 'root' influence (typically a civ center)
    482489    // belonging to their player, and mark them with the connected flag
     490    Grid<u8>& grid = *m_Territories;
     491    const u16 maxi = (u16)(grid.m_W-1);
     492    const u16 maxj = (u16)(grid.m_H-1);
     493
     494    std::vector<std::pair<u16, u16> > tileStack;
     495    // TODO: pre-allocate once and for all
     496    //tileStack.reserve(500);
    483497    for (std::vector<entity_id_t>::iterator it = rootInfluenceEntities.begin(); it != rootInfluenceEntities.end(); ++it)
    484498    {
    485499        // (These components must be valid else the entities wouldn't be added to this list)
    486500        CmpPtr<ICmpOwnership> cmpOwnership(GetSimContext(), *it);
    487501        CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), *it);
    488502
    489         CFixedVector2D pos = cmpPosition->GetPosition2D();
    490         u16 i = (u16)clamp((pos.X / (int)TERRAIN_TILE_SIZE).ToInt_RoundToNegInfinity(), 0, tilesW-1);
    491         u16 j = (u16)clamp((pos.Y / (int)TERRAIN_TILE_SIZE).ToInt_RoundToNegInfinity(), 0, tilesH-1);
     503        const CFixedVector2D pos = cmpPosition->GetPosition2D();
     504        const u16 i = (u16)clamp((pos.X / (int)TERRAIN_TILE_SIZE).ToInt_RoundToNegInfinity(), 0, tilesW-1);
     505        const u16 j = (u16)clamp((pos.Y / (int)TERRAIN_TILE_SIZE).ToInt_RoundToNegInfinity(), 0, tilesH-1);
    492506
    493         u8 owner = (u8)cmpOwnership->GetOwner();
     507        const u8 owner = (u8)cmpOwnership->GetOwner();
    494508
    495509        if (m_Territories->get(i, j) != owner)
    496510            continue;
    497511
    498512        // TODO: would be nice to refactor some of the many flood fill
    499513        // algorithms in this component
     514        tileStack.clear();
     515#define MARK_AND_PUSH(ki, kj) STMT(grid.set(ki, kj, owner | TERRITORY_CONNECTED_MASK); tileStack.push_back(std::make_pair(ki, kj)); )
    500516
    501         Grid<u8>& grid = *m_Territories;
    502 
    503         u16 maxi = (u16)(grid.m_W-1);
    504         u16 maxj = (u16)(grid.m_H-1);
    505 
    506         std::vector<std::pair<u16, u16> > tileStack;
    507 
    508 #define MARK_AND_PUSH(i, j) STMT(grid.set(i, j, owner | TERRITORY_CONNECTED_MASK); tileStack.push_back(std::make_pair(i, j)); )
    509 
    510517        MARK_AND_PUSH(i, j);
    511518        while (!tileStack.empty())
    512519        {
    513             int ti = tileStack.back().first;
    514             int tj = tileStack.back().second;
     520            const int ti = tileStack.back().first;
     521            const int tj = tileStack.back().second;
    515522            tileStack.pop_back();
    516523
    517524            if (ti > 0 && grid.get(ti-1, tj) == owner)
     
    743750    m_TerritoryManager.CalculateTerritories();
    744751}
    745752
    746 void TerritoryOverlay::ProcessTile(ssize_t i, ssize_t j)
     753void TerritoryOverlay::ProcessTile(const ssize_t i, const ssize_t j)
    747754{
    748755    if (!m_TerritoryManager.m_Territories)
    749756        return;
  • source/simulation2/components/CCmpPathfinder_Common.h

     
    240240
    241241    virtual const Grid<u16>& GetPassabilityGrid();
    242242
    243     virtual void ComputePath(entity_pos_t x0, entity_pos_t z0, const Goal& goal, pass_class_t passClass, cost_class_t costClass, Path& ret);
     243    virtual void ComputePath(const entity_pos_t x0, const entity_pos_t z0, const Goal& goal, const pass_class_t passClass, const cost_class_t costClass, Path& ret);
    244244
    245     virtual u32 ComputePathAsync(entity_pos_t x0, entity_pos_t z0, const Goal& goal, pass_class_t passClass, cost_class_t costClass, entity_id_t notify);
     245    virtual u32 ComputePathAsync(const entity_pos_t x0, const entity_pos_t z0, const Goal& goal, const pass_class_t passClass, const cost_class_t costClass, const entity_id_t notify);
    246246
    247     virtual void ComputeShortPath(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t r, entity_pos_t range, const Goal& goal, pass_class_t passClass, Path& ret);
     247    virtual void ComputeShortPath(const IObstructionTestFilter& filter, const entity_pos_t x0, const entity_pos_t z0, const entity_pos_t r, const entity_pos_t range, const Goal& goal, const pass_class_t passClass, Path& ret);
    248248
    249     virtual u32 ComputeShortPathAsync(entity_pos_t x0, entity_pos_t z0, entity_pos_t r, entity_pos_t range, const Goal& goal, pass_class_t passClass, bool avoidMovingUnits, entity_id_t controller, entity_id_t notify);
     249    virtual u32 ComputeShortPathAsync(const entity_pos_t x0, const entity_pos_t z0, const entity_pos_t r, const entity_pos_t range, const Goal& goal, const pass_class_t passClass, const bool avoidMovingUnits, const entity_id_t controller, const entity_id_t notify);
    250250
    251     virtual void SetDebugPath(entity_pos_t x0, entity_pos_t z0, const Goal& goal, pass_class_t passClass, cost_class_t costClass);
     251    virtual void SetDebugPath(const entity_pos_t x0, const entity_pos_t z0, const Goal& goal, const pass_class_t passClass, const cost_class_t costClass);
    252252
    253253    virtual void ResetDebugPath();
    254254
    255255    virtual void SetDebugOverlay(bool enabled);
    256256
    257     virtual fixed GetMovementSpeed(entity_pos_t x0, entity_pos_t z0, cost_class_t costClass);
     257    virtual fixed GetMovementSpeed( const entity_pos_t x0,  const entity_pos_t z0,  const cost_class_t costClass)  ;
    258258
    259     virtual CFixedVector2D GetNearestPointOnGoal(CFixedVector2D pos, const Goal& goal);
     259    virtual CFixedVector2D GetNearestPointOnGoal(const CFixedVector2D& pos, const Goal& goal) const;
    260260
    261261    virtual bool CheckMovement(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r, pass_class_t passClass);
    262262
     
    275275    /**
    276276     * Returns the tile containing the given position
    277277     */
    278     void NearestTile(entity_pos_t x, entity_pos_t z, u16& i, u16& j)
     278    void NearestTile( const entity_pos_t x,  const entity_pos_t z, u16& i, u16& j) const
    279279    {
    280280        i = (u16)clamp((x / (int)TERRAIN_TILE_SIZE).ToInt_RoundToZero(), 0, m_MapSize-1);
    281281        j = (u16)clamp((z / (int)TERRAIN_TILE_SIZE).ToInt_RoundToZero(), 0, m_MapSize-1);
     
    284284    /**
    285285     * Returns the position of the center of the given tile
    286286     */
    287     static void TileCenter(u16 i, u16 j, entity_pos_t& x, entity_pos_t& z)
     287    static void TileCenter(const u16 i, const u16 j, entity_pos_t& x, entity_pos_t& z) 
    288288    {
    289289        x = entity_pos_t::FromInt(i*(int)TERRAIN_TILE_SIZE + (int)TERRAIN_TILE_SIZE/2);
    290290        z = entity_pos_t::FromInt(j*(int)TERRAIN_TILE_SIZE + (int)TERRAIN_TILE_SIZE/2);
    291291    }
    292292
    293     static fixed DistanceToGoal(CFixedVector2D pos, const CCmpPathfinder::Goal& goal);
     293    static fixed DistanceToGoal(const CFixedVector2D& pos, const CCmpPathfinder::Goal& goal);
    294294
    295295    /**
    296296     * Regenerates the grid based on the current obstruction list, if necessary
     
    298298    void UpdateGrid();
    299299
    300300    void RenderSubmit(SceneCollector& collector);
     301    public:
     302       
     303    private:
    301304};
    302305
    303306#endif // INCLUDED_CCMPPATHFINDER_COMMON
  • source/simulation2/components/CCmpRangeManager.cpp

     
    5757 * Convert an owner ID (-1 = unowned, 0 = gaia, 1..30 = players)
    5858 * into a 32-bit mask for quick set-membership tests.
    5959 */
    60 static u32 CalcOwnerMask(player_id_t owner)
     60static u32 CalcOwnerMask(const player_id_t owner)
    6161{
    6262    if (owner >= -1 && owner < 31)
    6363        return 1 << (1+owner);
     
    6868/**
    6969 * Returns LOS mask for given player.
    7070 */
    71 static u32 CalcPlayerLosMask(player_id_t player)
     71static u32 CalcPlayerLosMask(const player_id_t player)
    7272{
    7373    if (player > 0 && player <= 16)
    7474        return ICmpRangeManager::LOS_MASK << (2*(player-1));
     
    7878/**
    7979 * Returns shared LOS mask for given list of players.
    8080 */
    81 static u32 CalcSharedLosMask(std::vector<player_id_t> players)
     81static u32 CalcSharedLosMask(const std::vector<player_id_t> &players)
    8282{
    8383    u32 playerMask = 0;
    8484    for (size_t i = 0; i < players.size(); i++)
     
    722722        // no entities will move until we've finished checking all the ranges
    723723        std::vector<std::pair<entity_id_t, CMessageRangeUpdate> > messages;
    724724
     725        std::vector<entity_id_t> r;
     726        std::vector<entity_id_t> added;
     727        std::vector<entity_id_t> removed;
     728
    725729        for (std::map<tag_t, Query>::iterator it = m_Queries.begin(); it != m_Queries.end(); ++it)
    726730        {
    727731            Query& q = it->second;
     
    733737            if (!cmpSourcePosition || !cmpSourcePosition->IsInWorld())
    734738                continue;
    735739
    736             std::vector<entity_id_t> r;
     740            r.clear();
    737741            r.reserve(q.lastMatch.size());
    738742
    739743            PerformQuery(q, r);
    740744
     745            added.clear();
     746            removed.clear();
    741747            // Compute the changes vs the last match
    742             std::vector<entity_id_t> added;
    743             std::vector<entity_id_t> removed;
    744748            std::set_difference(r.begin(), r.end(), q.lastMatch.begin(), q.lastMatch.end(), std::back_inserter(added));
    745749            std::set_difference(q.lastMatch.begin(), q.lastMatch.end(), r.begin(), r.end(), std::back_inserter(removed));
    746750
    747751            if (added.empty() && removed.empty())
    748752                continue;
    749753
     754
    750755            // Return the 'added' list sorted by distance from the entity
    751756            // (Don't bother sorting 'removed' because they might not even have positions or exist any more)
    752             CFixedVector2D pos = cmpSourcePosition->GetPosition2D();
     757            const CFixedVector2D pos (cmpSourcePosition->GetPosition2D());
    753758            std::stable_sort(added.begin(), added.end(), EntityDistanceOrdering(m_EntityData, pos));
    754759
    755760            messages.push_back(std::make_pair(q.source, CMessageRangeUpdate(it->first)));
     
    799804        CmpPtr<ICmpPosition> cmpSourcePosition(GetSimContext(), q.source);
    800805        if (!cmpSourcePosition || !cmpSourcePosition->IsInWorld())
    801806            return;
    802         CFixedVector2D pos = cmpSourcePosition->GetPosition2D();
     807        const CFixedVector2D pos (cmpSourcePosition->GetPosition2D());
    803808
    804809        // Special case: range -1.0 means check all entities ignoring distance
    805810        if (q.maxRange == entity_pos_t::FromInt(-1))
     
    815820        else
    816821        {
    817822            // Get a quick list of entities that are potentially in range
    818             std::vector<entity_id_t> ents = m_Subdivision.GetNear(pos, q.maxRange);
     823            std::vector<entity_id_t> ents;
     824            m_Subdivision.GetNear(pos, q.maxRange, ents);
    819825
    820826            for (size_t i = 0; i < ents.size(); ++i)
    821827            {
     
    826832                    continue;
    827833
    828834                // Restrict based on precise distance
    829                 int distVsMax = (CFixedVector2D(it->second.x, it->second.z) - pos).CompareLength(q.maxRange);
     835                const int distVsMax = (CFixedVector2D(it->second.x, it->second.z) - pos).CompareLength(q.maxRange);
    830836                if (distVsMax > 0)
    831837                    continue;
    832838
    833839                if (!q.minRange.IsZero())
    834840                {
    835                     int distVsMin = (CFixedVector2D(it->second.x, it->second.z) - pos).CompareLength(q.minRange);
     841                    const int distVsMin = (CFixedVector2D(it->second.x, it->second.z) - pos).CompareLength(q.minRange);
    836842                    if (distVsMin < 0)
    837843                        continue;
    838844                }
     
    970976
    971977    // LOS implementation:
    972978
    973     virtual CLosQuerier GetLosQuerier(player_id_t player)
     979    virtual CLosQuerier GetLosQuerier(const player_id_t player)
    974980    {
    975981        if (GetLosRevealAll(player))
    976982            return CLosQuerier(0xFFFFFFFFu, m_LosStateRevealed, m_TerrainVerticesPerSide);
     
    978984            return CLosQuerier(GetSharedLosMask(player), m_LosState, m_TerrainVerticesPerSide);
    979985    }
    980986
    981     virtual ELosVisibility GetLosVisibility(entity_id_t ent, player_id_t player, bool forceRetainInFog)
     987    virtual ELosVisibility GetLosVisibility(const entity_id_t ent, const player_id_t player, const bool forceRetainInFog)
    982988    {
    983989        // (We can't use m_EntityData since this needs to handle LOCAL entities too)
    984990
     
    987993        if (!cmpPosition || !cmpPosition->IsInWorld())
    988994            return VIS_HIDDEN;
    989995
    990         CFixedVector2D pos = cmpPosition->GetPosition2D();
     996        const CFixedVector2D pos (cmpPosition->GetPosition2D());
    991997
    992         int i = (pos.X / (int)TERRAIN_TILE_SIZE).ToInt_RoundToNearest();
    993         int j = (pos.Y / (int)TERRAIN_TILE_SIZE).ToInt_RoundToNearest();
     998        const int i = (pos.X / (int)TERRAIN_TILE_SIZE).ToInt_RoundToNearest();
     999        const int j = (pos.Y / (int)TERRAIN_TILE_SIZE).ToInt_RoundToNearest();
    9941000
    9951001        // Reveal flag makes all positioned entities visible
    9961002        if (GetLosRevealAll(player))
     
    10191025        return VIS_HIDDEN;
    10201026    }
    10211027
    1022     virtual void SetLosRevealAll(player_id_t player, bool enabled)
     1028    virtual void SetLosRevealAll(const player_id_t player, const bool enabled)
    10231029    {
    10241030        m_LosRevealAll[player] = enabled;
    10251031    }
    10261032
    1027     virtual bool GetLosRevealAll(player_id_t player)
     1033    virtual bool GetLosRevealAll(const player_id_t player)
    10281034    {
    10291035        std::map<player_id_t, bool>::const_iterator it;
    10301036
     
    10411047        return false;
    10421048    }
    10431049
    1044     virtual void SetLosCircular(bool enabled)
     1050    virtual void SetLosCircular(const bool enabled)
    10451051    {
    10461052        m_LosCircular = enabled;
    10471053
     
    10581064        m_SharedLosMasks[player] = CalcSharedLosMask(players);
    10591065    }
    10601066
    1061     virtual u32 GetSharedLosMask(player_id_t player)
     1067    virtual u32 GetSharedLosMask(const player_id_t player)
    10621068    {
    10631069        std::map<player_id_t, u32>::const_iterator it = m_SharedLosMasks.find(player);
    10641070        ENSURE(it != m_SharedLosMasks.end());
     
    10981104     * Returns whether the given vertex is outside the normal bounds of the world
    10991105     * (i.e. outside the range of a circular map)
    11001106     */
    1101     inline bool LosIsOffWorld(ssize_t i, ssize_t j)
     1107    inline bool LosIsOffWorld(const ssize_t i, const ssize_t j) const
    11021108    {
    11031109        // WARNING: CCmpObstructionManager::Rasterise needs to be kept in sync with this
    11041110        const ssize_t edgeSize = 3; // number of vertexes around the edge that will be off-world
     
    11071113        {
    11081114            // With a circular map, vertex is off-world if hypot(i - size/2, j - size/2) >= size/2:
    11091115
    1110             ssize_t dist2 = (i - m_TerrainVerticesPerSide/2)*(i - m_TerrainVerticesPerSide/2)
     1116            const ssize_t dist2 = (i - m_TerrainVerticesPerSide/2)*(i - m_TerrainVerticesPerSide/2)
    11111117                    + (j - m_TerrainVerticesPerSide/2)*(j - m_TerrainVerticesPerSide/2);
    11121118
    1113             ssize_t r = m_TerrainVerticesPerSide/2 - edgeSize + 1;
     1119            const ssize_t r = m_TerrainVerticesPerSide/2 - edgeSize + 1;
    11141120                // subtract a bit from the radius to ensure nice
    11151121                // SoD blurring around the edges of the map
    11161122
     
    11281134    /**
    11291135     * Update the LOS state of tiles within a given horizontal strip (i0,j) to (i1,j) (inclusive).
    11301136     */
    1131     inline void LosAddStripHelper(u8 owner, i32 i0, i32 i1, i32 j, u16* counts)
     1137    inline void LosAddStripHelper(const u8 owner, const i32 i0, const i32 i1, const i32 j, u16* const __restrict counts)
    11321138    {
    11331139        if (i1 < i0)
    11341140            return;
    11351141
    1136         i32 idx0 = j*m_TerrainVerticesPerSide + i0;
    1137         i32 idx1 = j*m_TerrainVerticesPerSide + i1;
     1142        const i32 idx0 = j*m_TerrainVerticesPerSide + i0;
     1143        const i32 idx1 = j*m_TerrainVerticesPerSide + i1;
    11381144
    11391145        for (i32 idx = idx0; idx <= idx1; ++idx)
    11401146        {
    11411147            // Increasing from zero to non-zero - move from unexplored/explored to visible+explored
    11421148            if (counts[idx] == 0)
    11431149            {
    1144                 i32 i = i0 + idx - idx0;
     1150                const i32 i = i0 + idx - idx0;
    11451151                if (!LosIsOffWorld(i, j))
    11461152                    m_LosState[idx] |= ((LOS_VISIBLE | LOS_EXPLORED) << (2*(owner-1)));
    11471153            }
     
    11541160    /**
    11551161     * Update the LOS state of tiles within a given horizontal strip (i0,j) to (i1,j) (inclusive).
    11561162     */
    1157     inline void LosRemoveStripHelper(u8 owner, i32 i0, i32 i1, i32 j, u16* counts)
     1163    inline void LosRemoveStripHelper(const u8 owner, const i32 i0, const i32 i1, const i32 j, u16* const __restrict counts)
    11581164    {
    11591165        if (i1 < i0)
    11601166            return;
    11611167
    1162         i32 idx0 = j*m_TerrainVerticesPerSide + i0;
    1163         i32 idx1 = j*m_TerrainVerticesPerSide + i1;
     1168        const i32 idx0 = j*m_TerrainVerticesPerSide + i0;
     1169        const i32 idx1 = j*m_TerrainVerticesPerSide + i1;
    11641170
    11651171        for (i32 idx = idx0; idx <= idx1; ++idx)
    11661172        {
     
    11821188     * Assumes owner is in the valid range.
    11831189     */
    11841190    template<bool adding>
    1185     void LosUpdateHelper(u8 owner, entity_pos_t visionRange, CFixedVector2D pos)
     1191    void LosUpdateHelper(const u8 owner, const entity_pos_t visionRange, const CFixedVector2D& pos)
    11861192    {
    11871193        if (m_TerrainVerticesPerSide == 0) // do nothing if not initialised yet
    11881194            return;
     
    12081214
    12091215        // Compute top/bottom coordinates, and clamp to exclude the 1-tile border around the map
    12101216        // (so that we never render the sharp edge of the map)
    1211         i32 j0 = ((pos.Y - visionRange)/(int)TERRAIN_TILE_SIZE).ToInt_RoundToInfinity();
    1212         i32 j1 = ((pos.Y + visionRange)/(int)TERRAIN_TILE_SIZE).ToInt_RoundToNegInfinity();
    1213         i32 j0clamp = std::max(j0, 1);
    1214         i32 j1clamp = std::min(j1, m_TerrainVerticesPerSide-2);
     1217        const i32 j0 = ((pos.Y - visionRange)/(int)TERRAIN_TILE_SIZE).ToInt_RoundToInfinity();
     1218        const i32 j1 = ((pos.Y + visionRange)/(int)TERRAIN_TILE_SIZE).ToInt_RoundToNegInfinity();
     1219        const i32 j0clamp = std::max(j0, 1);
     1220        const i32 j1clamp = std::min(j1, m_TerrainVerticesPerSide-2);
    12151221
    12161222        // Translate world coordinates into fractional tile-space coordinates
    1217         entity_pos_t x = pos.X / (int)TERRAIN_TILE_SIZE;
    1218         entity_pos_t y = pos.Y / (int)TERRAIN_TILE_SIZE;
    1219         entity_pos_t r = visionRange / (int)TERRAIN_TILE_SIZE;
    1220         entity_pos_t r2 = r.Square();
     1223        const entity_pos_t x = pos.X / (int)TERRAIN_TILE_SIZE;
     1224        const entity_pos_t y = pos.Y / (int)TERRAIN_TILE_SIZE;
     1225        const entity_pos_t r = visionRange / (int)TERRAIN_TILE_SIZE;
     1226        const entity_pos_t r2 = r.Square();
    12211227
    12221228        // Compute the integers on either side of x
    1223         i32 xfloor = (x - entity_pos_t::Epsilon()).ToInt_RoundToNegInfinity();
    1224         i32 xceil = (x + entity_pos_t::Epsilon()).ToInt_RoundToInfinity();
     1229        const i32 xfloor = (x - entity_pos_t::Epsilon()).ToInt_RoundToNegInfinity();
     1230        const i32 xceil = (x + entity_pos_t::Epsilon()).ToInt_RoundToInfinity();
    12251231
    12261232        // Initialise the strip (i0, i1) to a rough guess
    12271233        i32 i0 = xfloor;
     
    12571263
    12581264            // Clamp the strip to exclude the 1-tile border,
    12591265            // then add or remove the strip as requested
    1260             i32 i0clamp = std::max(i0, 1);
    1261             i32 i1clamp = std::min(i1, m_TerrainVerticesPerSide-2);
     1266            const i32 i0clamp = std::max(i0, 1);
     1267            const i32 i1clamp = std::min(i1, m_TerrainVerticesPerSide-2);
    12621268            if (adding)
    12631269                LosAddStripHelper(owner, i0clamp, i1clamp, j, countsData);
    12641270            else
     
    12711277     * by removing visibility around the 'from' position
    12721278     * and then adding visibility around the 'to' position.
    12731279     */
    1274     void LosUpdateHelperIncremental(u8 owner, entity_pos_t visionRange, CFixedVector2D from, CFixedVector2D to)
     1280    void LosUpdateHelperIncremental(const u8 owner, const entity_pos_t visionRange, const CFixedVector2D& from, const CFixedVector2D& to)
    12751281    {
    12761282        if (m_TerrainVerticesPerSide == 0) // do nothing if not initialised yet
    12771283            return;
     
    12841290        if (counts.empty())
    12851291            counts.resize(m_TerrainVerticesPerSide*m_TerrainVerticesPerSide);
    12861292
    1287         u16* countsData = &counts[0];
     1293        u16* const __restrict countsData = &counts[0];
    12881294
    12891295        // See comments in LosUpdateHelper.
    12901296        // This does exactly the same, except computing the strips for
     
    12931299        // so we can compute the difference between the removed/added strips
    12941300        // and only have to touch tiles that have a net change.)
    12951301
    1296         i32 j0_from = ((from.Y - visionRange)/(int)TERRAIN_TILE_SIZE).ToInt_RoundToInfinity();
    1297         i32 j1_from = ((from.Y + visionRange)/(int)TERRAIN_TILE_SIZE).ToInt_RoundToNegInfinity();
    1298         i32 j0_to = ((to.Y - visionRange)/(int)TERRAIN_TILE_SIZE).ToInt_RoundToInfinity();
    1299         i32 j1_to = ((to.Y + visionRange)/(int)TERRAIN_TILE_SIZE).ToInt_RoundToNegInfinity();
    1300         i32 j0clamp = std::max(std::min(j0_from, j0_to), 1);
    1301         i32 j1clamp = std::min(std::max(j1_from, j1_to), m_TerrainVerticesPerSide-2);
     1302        const i32 j0_from = ((from.Y - visionRange)/(int)TERRAIN_TILE_SIZE).ToInt_RoundToInfinity();
     1303        const i32 j1_from = ((from.Y + visionRange)/(int)TERRAIN_TILE_SIZE).ToInt_RoundToNegInfinity();
     1304        const i32 j0_to = ((to.Y - visionRange)/(int)TERRAIN_TILE_SIZE).ToInt_RoundToInfinity();
     1305        const i32 j1_to = ((to.Y + visionRange)/(int)TERRAIN_TILE_SIZE).ToInt_RoundToNegInfinity();
     1306        const i32 j0clamp = std::max(std::min(j0_from, j0_to), 1);
     1307        const i32 j1clamp = std::min(std::max(j1_from, j1_to), m_TerrainVerticesPerSide-2);
    13021308
    1303         entity_pos_t x_from = from.X / (int)TERRAIN_TILE_SIZE;
    1304         entity_pos_t y_from = from.Y / (int)TERRAIN_TILE_SIZE;
    1305         entity_pos_t x_to = to.X / (int)TERRAIN_TILE_SIZE;
    1306         entity_pos_t y_to = to.Y / (int)TERRAIN_TILE_SIZE;
    1307         entity_pos_t r = visionRange / (int)TERRAIN_TILE_SIZE;
    1308         entity_pos_t r2 = r.Square();
     1309        const entity_pos_t x_from = from.X / (int)TERRAIN_TILE_SIZE;
     1310        const entity_pos_t y_from = from.Y / (int)TERRAIN_TILE_SIZE;
     1311        const entity_pos_t x_to = to.X / (int)TERRAIN_TILE_SIZE;
     1312        const entity_pos_t y_to = to.Y / (int)TERRAIN_TILE_SIZE;
     1313        const entity_pos_t r = visionRange / (int)TERRAIN_TILE_SIZE;
     1314        const entity_pos_t r2 = r.Square();
    13091315
    1310         i32 xfloor_from = (x_from - entity_pos_t::Epsilon()).ToInt_RoundToNegInfinity();
    1311         i32 xceil_from = (x_from + entity_pos_t::Epsilon()).ToInt_RoundToInfinity();
    1312         i32 xfloor_to = (x_to - entity_pos_t::Epsilon()).ToInt_RoundToNegInfinity();
    1313         i32 xceil_to = (x_to + entity_pos_t::Epsilon()).ToInt_RoundToInfinity();
     1316        const i32 xfloor_from = (x_from - entity_pos_t::Epsilon()).ToInt_RoundToNegInfinity();
     1317        const i32 xceil_from = (x_from + entity_pos_t::Epsilon()).ToInt_RoundToInfinity();
     1318        const i32 xfloor_to = (x_to - entity_pos_t::Epsilon()).ToInt_RoundToNegInfinity();
     1319        const i32 xceil_to = (x_to + entity_pos_t::Epsilon()).ToInt_RoundToInfinity();
    13141320
    13151321        i32 i0_from = xfloor_from;
    13161322        i32 i1_from = xceil_from;
     
    13191325
    13201326        for (i32 j = j0clamp; j <= j1clamp; ++j)
    13211327        {
    1322             entity_pos_t dy_from = entity_pos_t::FromInt(j) - y_from;
    1323             entity_pos_t dy2_from = dy_from.Square();
     1328            const entity_pos_t dy_from = entity_pos_t::FromInt(j) - y_from;
     1329            const entity_pos_t dy2_from = dy_from.Square();
    13241330            while (dy2_from + (entity_pos_t::FromInt(i0_from-1) - x_from).Square() <= r2)
    13251331                --i0_from;
    13261332            while (i0_from < xceil_from && dy2_from + (entity_pos_t::FromInt(i0_from) - x_from).Square() > r2)
     
    13301336            while (i1_from > xfloor_from && dy2_from + (entity_pos_t::FromInt(i1_from) - x_from).Square() > r2)
    13311337                --i1_from;
    13321338
    1333             entity_pos_t dy_to = entity_pos_t::FromInt(j) - y_to;
    1334             entity_pos_t dy2_to = dy_to.Square();
     1339            const entity_pos_t dy_to = entity_pos_t::FromInt(j) - y_to;
     1340            const entity_pos_t dy2_to = dy_to.Square();
    13351341            while (dy2_to + (entity_pos_t::FromInt(i0_to-1) - x_to).Square() <= r2)
    13361342                --i0_to;
    13371343            while (i0_to < xceil_to && dy2_to + (entity_pos_t::FromInt(i0_to) - x_to).Square() > r2)
     
    13611367            // Check whether this strip moved at all
    13621368            if (!(i0_to == i0_from && i1_to == i1_from))
    13631369            {
    1364                 i32 i0clamp_from = std::max(i0_from, 1);
    1365                 i32 i1clamp_from = std::min(i1_from, m_TerrainVerticesPerSide-2);
    1366                 i32 i0clamp_to = std::max(i0_to, 1);
    1367                 i32 i1clamp_to = std::min(i1_to, m_TerrainVerticesPerSide-2);
     1370                const i32 i0clamp_from = std::max(i0_from, 1);
     1371                const i32 i1clamp_from = std::min(i1_from, m_TerrainVerticesPerSide-2);
     1372                const i32 i0clamp_to = std::max(i0_to, 1);
     1373                const i32 i1clamp_to = std::min(i1_to, m_TerrainVerticesPerSide-2);
    13681374
    13691375                // Check whether one strip is negative width,
    13701376                // and we can just add/remove the entire other strip
     
    13961402        }
    13971403    }
    13981404
    1399     void LosAdd(player_id_t owner, entity_pos_t visionRange, CFixedVector2D pos)
     1405    void LosAdd(const player_id_t owner, const entity_pos_t visionRange, const CFixedVector2D& pos)
    14001406    {
    14011407        if (visionRange.IsZero() || owner <= 0 || owner > MAX_LOS_PLAYER_ID)
    14021408            return;
     
    14041410        LosUpdateHelper<true>((u8)owner, visionRange, pos);
    14051411    }
    14061412
    1407     void LosRemove(player_id_t owner, entity_pos_t visionRange, CFixedVector2D pos)
     1413    void LosRemove(const player_id_t owner, const entity_pos_t visionRange, const CFixedVector2D& pos)
    14081414    {
    14091415        if (visionRange.IsZero() || owner <= 0 || owner > MAX_LOS_PLAYER_ID)
    14101416            return;
     
    14121418        LosUpdateHelper<false>((u8)owner, visionRange, pos);
    14131419    }
    14141420
    1415     void LosMove(player_id_t owner, entity_pos_t visionRange, CFixedVector2D from, CFixedVector2D to)
     1421    void LosMove(const player_id_t owner, const entity_pos_t visionRange, const CFixedVector2D& from, const CFixedVector2D& to)
    14161422    {
    14171423        if (visionRange.IsZero() || owner <= 0 || owner > MAX_LOS_PLAYER_ID)
    14181424            return;
     
    14321438        }
    14331439    }
    14341440
    1435     virtual i32 GetPercentMapExplored(player_id_t player)
     1441    virtual i32 GetPercentMapExplored(const player_id_t player)
    14361442    {
    14371443        i32 exploredVertices = 0;
    14381444        i32 overallVisibleVertices = 0;