Advertisement
Guest User

SAPDivision.cpp

a guest
Sep 24th, 2013
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.57 KB | None | 0 0
  1. /* Copyright (C) 2013 Wildfire Games.
  2.  * This file is part of 0 A.D.
  3.  *
  4.  * 0 A.D. is free software: you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation, either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * 0 A.D. is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
  16.  */
  17. //#include "precompiled.h"
  18. #include "SAPDivision.h"
  19.  
  20.  
  21.  
  22.  
  23.     SAPDivision::SAPDivision()
  24.     {
  25.         m_XAxis.reserve(1024);
  26.     }
  27.     SAPDivision::~SAPDivision()
  28.     {
  29.         Destroy();
  30.     }
  31.  
  32.  
  33.     SAPDivision::SAPDivision(const SAPDivision& rhs)
  34.     {
  35.         this->operator=(rhs);
  36.     }
  37.     SAPDivision& SAPDivision::operator=(const SAPDivision& rhs)
  38.     {
  39.         if (this != &rhs)
  40.         {
  41.             Clear();
  42.  
  43.             if (int count = rhs.m_XAxis.size())
  44.             {
  45.                 m_XAxis.resize(count);
  46.                 memcpy(&m_XAxis[0], &rhs.m_XAxis[0], sizeof(SAPNode) * count);
  47.                 m_LiveHandles.reserve(count);
  48.                 for (int i = 0; i < count; ++i)
  49.                 {
  50.                     SAPHandle* handle = AllocHandle();
  51.                     handle->index = i;
  52.                     handle->entity = m_XAxis[i].handle->entity; // grab ptr from other Handle
  53.                     m_XAxis[i].handle = handle; // set the new handle
  54.                     m_LiveHandles.push_back(handle);
  55.                 }
  56.             }
  57.         }
  58.         return *this;
  59.     }
  60.  
  61.  
  62.     SAPHandle* SAPDivision::AllocHandle()
  63.     {
  64.         SAPHandle* handle;
  65.         if (!m_FreeHandles.empty()) // try to reuse a handle in freehandles
  66.         {
  67.             handle = m_FreeHandles.back();
  68.             m_FreeHandles.pop_back();
  69.         }
  70.         else handle = new SAPHandle;
  71.         m_LiveHandles.push_back(handle);
  72.         return handle;
  73.     }
  74.  
  75.  
  76.     void SAPDivision::Clear()
  77.     {
  78.         for (size_t i = 0; i < m_LiveHandles.size(); ++i)
  79.             m_FreeHandles.push_back(m_LiveHandles[i]); // push all live handles to freed
  80.         m_XAxis.clear();
  81.         m_LiveHandles.clear();
  82.         m_FreeHandles.clear();
  83.     }
  84.  
  85.  
  86.     void SAPDivision::Destroy()
  87.     {
  88.         for (size_t i = 0; i < m_LiveHandles.size(); ++i)
  89.             delete m_LiveHandles[i];
  90.         for (size_t i = 0; i < m_FreeHandles.size(); ++i)
  91.             delete m_FreeHandles[i];
  92.         m_XAxis.clear();
  93.         m_LiveHandles.clear();
  94.         m_FreeHandles.clear();
  95.     }
  96.  
  97.  
  98.     // fixes axis indices starting from the specified index (inclusive)
  99.     // fix_axis(Axis, 0, Axis.size() - 1) iterates and fixes the entire axis
  100.     static void axis_fix_indices(SAPNode* axis, int fromIndex, int toIndex)
  101.     {
  102.         for (int i = fromIndex; i <= toIndex; ++i)
  103.             axis[i].handle->index = i;
  104.     }
  105.     static int axis_insert_node(std::vector<SAPNode>& axis, const SAPNode& node)
  106.     {
  107.         int imin = 0;
  108.         if(int imax = axis.size())
  109.         {
  110.             SAPNode* data = &axis[0];
  111.             float targetXMin = node.x_min;
  112.             while(imin < imax) // binary-search
  113.             {
  114.                 const int imid = (imin + imax) >> 1;
  115.                 if(data[imid].x_min < targetXMin)
  116.                     imin = imid + 1;
  117.                 else
  118.                     imax = imid;
  119.             }
  120.         }
  121.         axis.insert(axis.begin() + imin, node);
  122.         return imin;
  123.     }
  124.     SAPHandle* SAPDivision::Insert(CEntityHandle* entity, const Vector2& toMin, const Vector2& toMax)
  125.     {
  126.         SAPHandle* handle = AllocHandle();
  127.  
  128.         SAPNode node; // create new SAPNode:
  129.         node.x_min = toMin.x;
  130.         node.x_max = toMax.x;
  131.         node.z_min = toMin.y;
  132.         node.z_max = toMax.y;
  133.         node.x_pos = (toMin.x + toMax.x) / 2;
  134.         node.z_pos = (toMin.y + toMax.y) / 2;
  135.         node.handle = handle;
  136.  
  137.         int index = axis_insert_node(m_XAxis, node);
  138.         axis_fix_indices(&m_XAxis[0], index + 1, m_XAxis.size() - 1);
  139.  
  140.         handle->index = index;
  141.         handle->entity = entity;
  142.         return handle;
  143.     }
  144.  
  145.     static void erase_first(std::vector<SAPHandle*>& vec, const SAPHandle* value)
  146.     {
  147.         if (const int count = vec.size()) {
  148.             SAPHandle** data = &vec[0];
  149.             for (int i = 0; i < count; ++i)
  150.                 if (data[i] == value)
  151.                     { vec.erase(vec.begin() + i); return; }
  152.         }
  153.     }
  154.     void SAPDivision::Remove(SAPHandle* handle)
  155.     {
  156.         m_XAxis.erase(m_XAxis.begin() + handle->index);
  157.         axis_fix_indices(&m_XAxis[0], handle->index, m_XAxis.size() - 1);
  158.  
  159.         // remove from live handles and throw it into freelist, so we can reuse it cheaply
  160.         erase_first(m_LiveHandles, handle);
  161.         m_FreeHandles.push_back(handle);
  162.     }
  163.  
  164.  
  165.     static bool swap_handle(SAPNode* pOld, SAPNode* pNew)
  166.     {
  167.         SAPNode temp = *pOld;
  168.         intptr_t size = (intptr_t)pNew - (intptr_t)pOld; // get the difference
  169.         bool forward;
  170.         if (size > 0)   forward = true;                 // is the target forward in axis?
  171.         else            forward = false, size = -size;  // the target is backward in axis.
  172.        
  173.         if (size == sizeof(SAPNode)) // only 1 element swap
  174.         {
  175.             *pOld = *pNew;
  176.             *pNew = temp;
  177.             return false; // no change to axis order
  178.         }
  179.         if (forward) memmove(pOld, pOld + 1, size); // move the whole block backwards
  180.         else         memmove(pOld + 1, pOld, size); // move the whole block forward
  181.         *pNew = temp; // write the handle
  182.         return true; // elements were shifted, axis is invalidated :(
  183.     }
  184.     void SAPDivision::Move(SAPHandle* handle, const Vector2& pos)
  185.     {
  186.         const int iOld  = handle->index;        // old (current) axis index
  187.         SAPNode* xAxis  = &m_XAxis[0];
  188.         SAPNode* node   = &xAxis[iOld];
  189.  
  190.         float dX = pos.x - node->x_pos; // delta movement in X axis
  191.         if (dX != 0.0f) // move in XAXIS
  192.         {
  193.             const int iLastX = m_XAxis.size() - 1;      // last valid index
  194.             const float xMin = node->x_min + dX;        // new MIN value in X axis
  195.             int iNew         = iOld;                    // new axis index
  196.            
  197.             if (dX > 0.0f)
  198.                  while (iNew != iLastX && xAxis[iNew + 1].x_min < xMin) ++iNew; // forward in X axis
  199.             else while (iNew != 0 && xAxis[iNew - 1].x_min > xMin) --iNew;      // backwards in X axis
  200.            
  201.             if (iNew != iOld) // did anything change?
  202.             {
  203.                 if (swap_handle(xAxis + iOld, xAxis + iNew))
  204.                 {
  205.                     axis_fix_indices(xAxis, iOld, iNew);    // update a range of indices
  206.                 }
  207.                 else
  208.                 {
  209.                     handle->index = iNew;                   // update the swapped value indices:
  210.                     xAxis[iOld].handle->index = iOld;
  211.                 }
  212.                 node = &xAxis[iNew]; // make sure to update the pointer after we swapped
  213.             }
  214.             node->x_min += dX;
  215.             node->x_max += dX;
  216.             node->x_pos = pos.x; // update position
  217.         }
  218.  
  219.         float dZ = pos.y - node->z_pos; // delta movement in Z axis
  220.         if (dZ != 0.0f) // move in ZAXIS
  221.         {
  222.             node->z_min += dZ;
  223.             node->z_max += dZ;
  224.             node->z_pos = pos.y;
  225.         }
  226.     }
  227.  
  228.  
  229.     static inline void insert_inrange(SAPRangeQuery& inrange, SAPHandle* handle, float sqrange)
  230.     {
  231.         if (inrange.count == SAPRangeQuery::MAX_COUNT)
  232.         {
  233.             assert(0 && "SAPRangeQuery::MAX_COUNT[2048] exceeded! Increase capacity.");
  234.             return;
  235.         }
  236.         SAPRangeQuery::Result& r = inrange.items[inrange.count++];
  237.         r.sqrange = sqrange;
  238.         r.handle = handle;
  239.     }
  240.  
  241.     void SAPDivision::GetInBoundingBox(SAPRangeQuery& inrange, const Vector2& min, const Vector2& max)
  242.     {
  243.  
  244.     }
  245.  
  246.     int SAPDivision::GetInEntityRange(SAPRangeQuery& inrange, SAPHandle* handle, float range)
  247.     {
  248.         inrange.clear();
  249.  
  250.         SAPNode* xAxis  = &m_XAxis[0];
  251.         SAPNode* xEnd   = &xAxis[m_XAxis.size()];
  252.         SAPNode* left   = &xAxis[handle->index - 1];
  253.         SAPNode* right  = &xAxis[handle->index + 1];
  254.        
  255.         const float sqRange = range * range;
  256.         const float outRange = 2 * range;
  257.         const float x_pos   = xAxis[handle->index].x_pos;
  258.         const float z_pos   = xAxis[handle->index].z_pos;
  259.  
  260.         int iterations = 0;
  261.  
  262.         for (; left >= xAxis; --left) // scan LEFT in X axis
  263.         {
  264.             ++iterations;
  265.             const float dx = x_pos - left->x_max;
  266.             if (dx > range)
  267.                 break; // not in range and there will no longer be any in X axis
  268.  
  269.             float dz;
  270.             if (left->z_pos > z_pos)    dz = left->z_min - z_pos; // target is UP in Z axis
  271.             else                        dz = z_pos - left->z_max; // target is DOWN in Z axis
  272.             if (dz > range)
  273.                 continue; // negative match, continue scanning X axis
  274.  
  275.             const float sqlen = dx*dx + dz*dz;
  276.             if (sqlen <= sqRange) // is it in range?
  277.             {
  278.                 insert_inrange(inrange, left->handle, sqlen); // add it to the list
  279.             }
  280.         }
  281.  
  282.         for (; right != xEnd; ++right) // scan RIGHT in X axis
  283.         {
  284.             ++iterations;
  285.             const float dx = right->x_min - x_pos;
  286.             if (dx > range)
  287.                 break; // not in range and there will no longer be any in X axis
  288.  
  289.             float dz;
  290.             if (right->z_pos > z_pos)   dz = right->z_min - z_pos; // target is UP in Z axis
  291.             else                        dz = z_pos - right->z_max; // target is DOWN in Z axis
  292.             if (dz > range)
  293.                 continue; // negative match, continue scanning X axis
  294.  
  295.             const float sqlen = dx*dx + dz*dz;
  296.             if (sqlen <= sqRange) // is it in range?
  297.             {
  298.                 insert_inrange(inrange, right->handle, sqlen); // add it to the list
  299.             }
  300.         }
  301.         return iterations;
  302.     }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement