Ticket #3410: corners.patch
File corners.patch, 25.4 KB (added by , 9 years ago) |
---|
-
source/simulation2/components/CCmpObstructionManager.cpp
465 465 virtual bool TestStaticShape(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t a, entity_pos_t w, entity_pos_t h, std::vector<entity_id_t>* out); 466 466 virtual bool TestUnitShape(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t r, std::vector<entity_id_t>* out); 467 467 468 virtual void Rasterize(Grid<NavcellData>& grid, const std::vector<PathfinderPassability>& passClasses, bool fullUpdate);468 virtual void Rasterize(Grid<NavcellData>& grid, Grid<CornerPassability>& cornerGrid, const std::vector<PathfinderPassability>& passClasses, bool fullUpdate); 469 469 virtual void GetObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector<ObstructionSquare>& squares); 470 470 virtual void GetUnitsOnObstruction(const ObstructionSquare& square, std::vector<entity_id_t>& out, const IObstructionTestFilter& filter); 471 471 … … 647 647 return (m_WorldX0 <= p.X && p.X <= m_WorldX1 && m_WorldZ0 <= p.Y && p.Y <= m_WorldZ1); 648 648 } 649 649 650 void RasterizeHelper(Grid<NavcellData>& grid, ICmpObstructionManager::flags_t requireMask, bool fullUpdate, pass_class_t appliedMask, entity_pos_t clearance = fixed::Zero());650 void RasterizeHelper(Grid<NavcellData>& grid, Grid<CornerPassability>& cornerGrid, ICmpObstructionManager::flags_t requireMask, bool fullUpdate, pass_class_t appliedMask, entity_pos_t clearance = fixed::Zero()); 651 651 }; 652 652 653 653 REGISTER_COMPONENT_TYPE(ObstructionManager) … … 826 826 return false; // didn't collide, if we got this far 827 827 } 828 828 829 void CCmpObstructionManager::Rasterize(Grid<NavcellData>& grid, const std::vector<PathfinderPassability>& passClasses, bool fullUpdate)829 void CCmpObstructionManager::Rasterize(Grid<NavcellData>& grid, Grid<CornerPassability>& cornerGrid, const std::vector<PathfinderPassability>& passClasses, bool fullUpdate) 830 830 { 831 831 PROFILE3("Rasterize"); 832 832 … … 836 836 // Pass classes will get shapes rasterized on them depending on their Obstruction value. 837 837 // Classes with another value than "pathfinding" should not use Clearance. 838 838 839 std::map<entity_pos_t, u16> pathfindingMasks;840 u16foundationMask = 0;839 std::map<entity_pos_t, pass_class_t> pathfindingMasks; 840 pass_class_t foundationMask = 0; 841 841 for (const PathfinderPassability& passability : passClasses) 842 842 { 843 843 switch (passability.m_Obstructions) … … 863 863 // so they should be the only ones rasterized using with the help of m_Dirty*Shapes vectors. 864 864 865 865 for (auto& maskPair : pathfindingMasks) 866 RasterizeHelper(grid, FLAG_BLOCK_PATHFINDING, fullUpdate, maskPair.second, maskPair.first);866 RasterizeHelper(grid, cornerGrid, FLAG_BLOCK_PATHFINDING, fullUpdate, maskPair.second, maskPair.first); 867 867 868 RasterizeHelper(grid, FLAG_BLOCK_FOUNDATION, fullUpdate, foundationMask);868 RasterizeHelper(grid, cornerGrid, FLAG_BLOCK_FOUNDATION, fullUpdate, foundationMask); 869 869 870 870 m_DirtyStaticShapes.clear(); 871 871 m_DirtyUnitShapes.clear(); 872 872 } 873 873 874 void CCmpObstructionManager::RasterizeHelper(Grid<NavcellData>& grid, ICmpObstructionManager::flags_t requireMask, bool fullUpdate, pass_class_t appliedMask, entity_pos_t clearance)874 void CCmpObstructionManager::RasterizeHelper(Grid<NavcellData>& grid, Grid<CornerPassability>& cornerGrid, ICmpObstructionManager::flags_t requireMask, bool fullUpdate, pass_class_t appliedMask, entity_pos_t clearance) 875 875 { 876 ENSURE(grid.m_W == cornerGrid.m_W && grid.m_H == cornerGrid.m_H); 877 876 878 for (auto& pair : m_StaticShapes) 877 879 { 878 880 const StaticShape& shape = pair.second; … … 886 888 ObstructionSquare square = { shape.x, shape.z, shape.u, shape.v, shape.hw, shape.hh }; 887 889 SimRasterize::Spans spans; 888 890 SimRasterize::RasterizeRectWithClearance(spans, square, clearance, Pathfinding::NAVCELL_SIZE); 889 for ( SimRasterize::Span& span : spans)891 for (const SimRasterize::Span& span : spans) 890 892 { 891 893 i16 j = Clamp(span.j, (i16)0, (i16)(grid.m_H-1)); 892 894 i16 i0 = std::max(span.i0, (i16)0); … … 893 895 i16 i1 = std::min(span.i1, (i16)grid.m_W); 894 896 895 897 for (i16 i = i0; i < i1; ++i) 896 grid.set(i, j, grid.get(i, j) |appliedMask);898 Pathfinding::CombinedGridsSet(grid, cornerGrid, i, j, span.corners[i-span.i0], appliedMask); 897 899 } 898 900 } 899 901 … … 913 915 Pathfinding::NearestNavcell(center.X + r, center.Y + r, i1, j1, grid.m_W, grid.m_H); 914 916 for (u16 j = j0+1; j < j1; ++j) 915 917 for (u16 i = i0+1; i < i1; ++i) 916 grid.set(i, j, grid.get(i, j) |appliedMask);918 Pathfinding::CombinedGridsSet(grid, cornerGrid, i, j, Pathfinding::PassableCorner::NONE, appliedMask); 917 919 } 918 920 } 919 921 … … 1011 1013 { 1012 1014 if (j == span.j && span.i0 <= i && i < span.i1) 1013 1015 { 1014 out.push_back(shape.entity); 1015 break; 1016 if (span.corners[i-span.i0] == Pathfinding::PassableCorner::NONE) 1017 { 1018 out.push_back(shape.entity); 1019 break; 1020 } 1016 1021 } 1017 1022 } 1018 1023 } -
source/simulation2/components/CCmpPathfinder.cpp
50 50 m_MapSize = 0; 51 51 m_Grid = NULL; 52 52 m_TerrainOnlyGrid = NULL; 53 m_CornerGrid = NULL; 54 m_TerrainOnlyCornerGrid = NULL; 53 55 54 56 m_ObstructionsDirty.Clean(); 55 57 m_PreserveUpdateInformations = false; … … 107 109 108 110 SAFE_DELETE(m_Grid); 109 111 SAFE_DELETE(m_TerrainOnlyGrid); 112 SAFE_DELETE(m_CornerGrid); 113 SAFE_DELETE(m_TerrainOnlyCornerGrid); 110 114 } 111 115 112 116 struct SerializeLongRequest … … 266 270 * Euclidean distances; currently it effectively does dist=max(dx,dy) instead. 267 271 * This would only really be a problem for big clearances. 268 272 */ 269 static void ExpandImpassableCells(Grid<NavcellData>& grid, u16 clearance, pass_class_t mask)273 static void ExpandImpassableCells(Grid<NavcellData>& grid, Grid<CornerPassability>& cornerGrid, u16 clearance, pass_class_t mask) 270 274 { 271 275 PROFILE3("ExpandImpassableCells"); 272 276 … … 314 318 { 315 319 // Add the mask if blocked by at least one nearby cell 316 320 if (numBlocked) 317 grid.set(i, j, grid.get(i, j) |mask);321 Pathfinding::CombinedGridsSet(grid, cornerGrid, i, j, Pathfinding::PassableCorner::NONE, mask); 318 322 319 323 // Slide the numBlocked window along: 320 324 // remove the old j-clearance value, add the new (j+1)+clearance … … 464 468 { 465 469 SAFE_DELETE(m_Grid); 466 470 SAFE_DELETE(m_TerrainOnlyGrid); 471 SAFE_DELETE(m_CornerGrid); 472 SAFE_DELETE(m_TerrainOnlyCornerGrid); 467 473 } 468 474 469 475 // Initialise the terrain data when first needed … … 472 478 m_MapSize = terrainSize; 473 479 m_Grid = new Grid<NavcellData>(m_MapSize * Pathfinding::NAVCELLS_PER_TILE, m_MapSize * Pathfinding::NAVCELLS_PER_TILE); 474 480 m_TerrainOnlyGrid = new Grid<NavcellData>(m_MapSize * Pathfinding::NAVCELLS_PER_TILE, m_MapSize * Pathfinding::NAVCELLS_PER_TILE); 481 m_CornerGrid = new Grid<CornerPassability>(m_MapSize * Pathfinding::NAVCELLS_PER_TILE, m_MapSize * Pathfinding::NAVCELLS_PER_TILE); 482 m_TerrainOnlyCornerGrid = new Grid<CornerPassability>(m_MapSize * Pathfinding::NAVCELLS_PER_TILE, m_MapSize * Pathfinding::NAVCELLS_PER_TILE); 475 483 476 484 m_ObstructionsDirty.dirty = true; 477 485 m_ObstructionsDirty.globallyDirty = true; … … 493 501 TerrainUpdateHelper(); 494 502 495 503 *m_Grid = *m_TerrainOnlyGrid; 504 *m_CornerGrid = *m_TerrainOnlyCornerGrid; 496 505 497 506 m_TerrainDirty = false; 498 507 m_ObstructionsDirty.globalRecompute = true; … … 503 512 ENSURE(m_Grid->m_W == m_TerrainOnlyGrid->m_W && m_Grid->m_H == m_TerrainOnlyGrid->m_H); 504 513 memcpy(m_Grid->m_Data, m_TerrainOnlyGrid->m_Data, (m_Grid->m_W)*(m_Grid->m_H)*sizeof(NavcellData)); 505 514 515 ENSURE(m_CornerGrid->m_W == m_TerrainOnlyCornerGrid->m_W && m_CornerGrid->m_H == m_TerrainOnlyCornerGrid->m_H); 516 memcpy(m_CornerGrid->m_Data, m_TerrainOnlyCornerGrid->m_Data, (m_CornerGrid->m_W)*(m_CornerGrid->m_H)*sizeof(CornerPassability)); 517 506 518 m_ObstructionsDirty.globallyDirty = true; 507 519 } 508 520 else 509 521 { 510 522 ENSURE(m_Grid->m_W == m_ObstructionsDirty.dirtinessGrid.m_W && m_Grid->m_H == m_ObstructionsDirty.dirtinessGrid.m_H); 523 ENSURE(m_CornerGrid->m_W == m_ObstructionsDirty.dirtinessGrid.m_W && m_CornerGrid->m_H == m_ObstructionsDirty.dirtinessGrid.m_H); 511 524 ENSURE(m_Grid->m_W == m_TerrainOnlyGrid->m_W && m_Grid->m_H == m_TerrainOnlyGrid->m_H); 525 ENSURE(m_CornerGrid->m_W == m_TerrainOnlyCornerGrid->m_W && m_CornerGrid->m_H == m_TerrainOnlyCornerGrid->m_H); 512 526 513 527 for (u16 i = 0; i < m_ObstructionsDirty.dirtinessGrid.m_W; ++i) 514 528 for (u16 j = 0; j < m_ObstructionsDirty.dirtinessGrid.m_H; ++j) 515 529 if (m_ObstructionsDirty.dirtinessGrid.get(i, j) == 1) 530 { 516 531 m_Grid->set(i, j, m_TerrainOnlyGrid->get(i, j)); 532 m_CornerGrid->set(i, j, m_TerrainOnlyCornerGrid->get(i, j)); 533 } 517 534 } 518 535 519 536 // Add obstructions onto the grid 520 cmpObstructionManager->Rasterize(*m_Grid, m_PassClasses, m_ObstructionsDirty.globalRecompute);537 cmpObstructionManager->Rasterize(*m_Grid, *m_CornerGrid, m_PassClasses, m_ObstructionsDirty.globalRecompute); 521 538 522 539 // Update the long-range pathfinder 523 540 if (m_ObstructionsDirty.globallyDirty) … … 524 541 { 525 542 std::map<std::string, pass_class_t> nonPathfindingPassClasses, pathfindingPassClasses; 526 543 GetPassabilityClasses(nonPathfindingPassClasses, pathfindingPassClasses); 527 m_LongPathfinder.Reload(m_Grid, nonPathfindingPassClasses, pathfindingPassClasses );544 m_LongPathfinder.Reload(m_Grid, nonPathfindingPassClasses, pathfindingPassClasses, m_CornerGrid); 528 545 } 529 546 else 530 m_LongPathfinder.Update(m_Grid, m_ObstructionsDirty.dirtinessGrid );547 m_LongPathfinder.Update(m_Grid, m_ObstructionsDirty.dirtinessGrid, m_CornerGrid); 531 548 532 549 // Notify the units that their current paths can be invalid now 533 550 CMessagePassabilityMapChanged msg; … … 560 577 m_MapSize = terrainSize; 561 578 562 579 SAFE_DELETE(m_TerrainOnlyGrid); 580 SAFE_DELETE(m_TerrainOnlyCornerGrid); 563 581 m_TerrainOnlyGrid = new Grid<NavcellData>(m_MapSize * Pathfinding::NAVCELLS_PER_TILE, m_MapSize * Pathfinding::NAVCELLS_PER_TILE); 582 m_TerrainOnlyCornerGrid = new Grid<CornerPassability>(m_MapSize * Pathfinding::NAVCELLS_PER_TILE, m_MapSize * Pathfinding::NAVCELLS_PER_TILE); 564 583 } 565 584 566 585 Grid<u16> shoreGrid = ComputeShoreGrid(); … … 596 615 597 616 // Compute the passability for every class for this cell 598 617 NavcellData t = 0; 618 CornerPassability c = 0; 599 619 for (PathfinderPassability& passability : m_PassClasses) 620 { 600 621 if (!passability.IsPassable(depth, slope, shoredist)) 622 { 623 Pathfinding::SetPassableCornerBits(c, Pathfinding::PassableCorner::NONE, passability.m_Mask); 601 624 t |= passability.m_Mask; 625 } 626 } 602 627 603 628 m_TerrainOnlyGrid->set(i, j, t); 629 m_TerrainOnlyCornerGrid->set(i, j, c); 604 630 } 605 631 } 606 632 … … 631 657 + (j*2 + 1 - h)*(j*2 + 1 - h); 632 658 633 659 if (dist2 >= (w - 2*edgeSize) * (h - 2*edgeSize)) 634 m_TerrainOnlyGrid->set(i, j, m_TerrainOnlyGrid->get(i, j) |edgeMask);660 Pathfinding::CombinedGridsSet(*m_TerrainOnlyGrid, *m_TerrainOnlyCornerGrid, i, j, Pathfinding::PassableCorner::NONE, edgeMask); 635 661 } 636 662 } 637 663 } … … 639 665 { 640 666 for (u16 j = 0; j < h; ++j) 641 667 for (u16 i = 0; i < edgeSize; ++i) 642 m_TerrainOnlyGrid->set(i, j, m_TerrainOnlyGrid->get(i, j) |edgeMask);668 Pathfinding::CombinedGridsSet(*m_TerrainOnlyGrid, *m_TerrainOnlyCornerGrid, i, j, Pathfinding::PassableCorner::NONE, edgeMask); 643 669 for (u16 j = 0; j < h; ++j) 644 670 for (u16 i = w-edgeSize+1; i < w; ++i) 645 m_TerrainOnlyGrid->set(i, j, m_TerrainOnlyGrid->get(i, j) |edgeMask);671 Pathfinding::CombinedGridsSet(*m_TerrainOnlyGrid, *m_TerrainOnlyCornerGrid, i, j, Pathfinding::PassableCorner::NONE, edgeMask); 646 672 for (u16 j = 0; j < edgeSize; ++j) 647 673 for (u16 i = edgeSize; i < w-edgeSize+1; ++i) 648 m_TerrainOnlyGrid->set(i, j, m_TerrainOnlyGrid->get(i, j) |edgeMask);674 Pathfinding::CombinedGridsSet(*m_TerrainOnlyGrid, *m_TerrainOnlyCornerGrid, i, j, Pathfinding::PassableCorner::NONE, edgeMask); 649 675 for (u16 j = h-edgeSize+1; j < h; ++j) 650 676 for (u16 i = edgeSize; i < w-edgeSize+1; ++i) 651 m_TerrainOnlyGrid->set(i, j, m_TerrainOnlyGrid->get(i, j) |edgeMask);677 Pathfinding::CombinedGridsSet(*m_TerrainOnlyGrid, *m_TerrainOnlyCornerGrid, i, j, Pathfinding::PassableCorner::NONE, edgeMask); 652 678 } 653 679 654 680 if (!expandPassability) … … 665 691 continue; 666 692 667 693 int clearance = (passability.m_Clearance / Pathfinding::NAVCELL_SIZE).ToInt_RoundToInfinity(); 668 ExpandImpassableCells(*m_TerrainOnlyGrid, clearance, passability.m_Mask);694 ExpandImpassableCells(*m_TerrainOnlyGrid, *m_TerrainOnlyCornerGrid, clearance, passability.m_Mask); 669 695 } 670 696 } 671 697 -
source/simulation2/components/CCmpPathfinder_Common.h
108 108 u16 m_MapSize; // tiles per side 109 109 Grid<NavcellData>* m_Grid; // terrain/passability information 110 110 Grid<NavcellData>* m_TerrainOnlyGrid; // same as m_Grid, but only with terrain, to avoid some recomputations 111 Grid<CornerPassability>* m_CornerGrid; // corner terrain/passability information 112 Grid<CornerPassability>* m_TerrainOnlyCornerGrid; // same as m_CornerGrid, but only with terrain, to avoid some recomputations 111 113 112 114 // Update data, used for clever updates and then stored for the AI manager 113 115 GridUpdateInformation m_ObstructionsDirty; -
source/simulation2/components/ICmpObstructionManager.h
205 205 206 206 /** 207 207 * Convert the current set of shapes onto a navcell grid, for all passability classes contained in @p passClasses. 208 * Also computes the corner passabilities for each of those navcells. 208 209 * If @p fullUpdate is false, the function will only go through dirty shapes. 209 210 * Shapes are expanded by the @p passClasses clearances, by ORing their masks onto the @p grid. 210 211 */ 211 virtual void Rasterize(Grid<NavcellData>& grid, const std::vector<PathfinderPassability>& passClasses, bool fullUpdate) = 0;212 virtual void Rasterize(Grid<NavcellData>& grid, Grid<CornerPassability>& cornerGrid, const std::vector<PathfinderPassability>& passClasses, bool fullUpdate) = 0; 212 213 213 214 /** 214 215 * Gets dirtiness information and resets it afterwards. Then it's the role of CCmpPathfinder -
source/simulation2/helpers/LongPathfinder.cpp
986 986 m_DebugGoal = state.goal; 987 987 } 988 988 989 void LongPathfinder::GetPassablePoint(u16 i, u16 j, entity_pos_t& x, entity_pos_t& z, pass_class_t passClass) const 990 { 991 if (m_CornerGrid) 992 Pathfinding::NavcellCorner(i, j, x, z, Pathfinding::GetPassableCorner(m_CornerGrid->get(i, j), passClass)); 993 else 994 Pathfinding::NavcellCenter(i, j, x, z); 995 } 996 989 997 void LongPathfinder::ComputePathOffImpassable(entity_pos_t x0, entity_pos_t z0, const PathGoal& UNUSED(origGoal), pass_class_t passClass, WaypointPath& path) 990 998 { 991 999 u16 i0, j0; -
source/simulation2/helpers/LongPathfinder.h
185 185 186 186 void Reload(Grid<NavcellData>* passabilityGrid, 187 187 const std::map<std::string, pass_class_t>& nonPathfindingPassClassMasks, 188 const std::map<std::string, pass_class_t>& pathfindingPassClassMasks) 188 const std::map<std::string, pass_class_t>& pathfindingPassClassMasks, 189 Grid<CornerPassability>* cornerGrid = NULL) 189 190 { 190 191 m_Grid = passabilityGrid; 192 193 if (cornerGrid) 194 { 195 ASSERT(passabilityGrid->m_W == cornerGrid->m_W && passabilityGrid.m_H == cornerGrid.m_H); 196 m_CornerGrid = cornerGrid; 197 } 198 191 199 ASSERT(passabilityGrid->m_H == passabilityGrid->m_W); 192 200 m_GridSize = passabilityGrid->m_W; 193 201 … … 196 204 m_PathfinderHier.Recompute(passabilityGrid, nonPathfindingPassClassMasks, pathfindingPassClassMasks); 197 205 } 198 206 199 void Update(Grid<NavcellData>* passabilityGrid, const Grid<u8>& dirtinessGrid )207 void Update(Grid<NavcellData>* passabilityGrid, const Grid<u8>& dirtinessGrid, Grid<CornerPassability>* cornerGrid = NULL) 200 208 { 201 209 m_Grid = passabilityGrid; 210 211 if (cornerGrid) 212 { 213 ASSERT(passabilityGrid->m_W == cornerGrid->m_W && passabilityGrid.m_H == cornerGrid.m_H); 214 m_CornerGrid = cornerGrid; 215 } 216 202 217 ASSERT(passabilityGrid->m_H == passabilityGrid->m_W); 203 218 ASSERT(m_GridSize == passabilityGrid->m_H); 204 219 … … 250 265 } 251 266 252 267 Grid<NavcellData>* m_Grid; 268 Grid<CornerPassability>* m_CornerGrid; 253 269 u16 m_GridSize; 254 270 255 271 // Debugging - output from last pathfind operation: … … 285 301 // Helper functions for ComputePath 286 302 287 303 /** 304 * Use the corner grid, if any, to determine a passable point of the cell. 305 */ 306 void GetPassablePoint(u16 i, u16 j, entity_pos_t& x, entity_pos_t& z, pass_class_t passClass) const; 307 308 /** 288 309 * Same kind of interface as ComputePath, but works when the unit is starting 289 310 * on an impassable navcell. 290 311 * Returns a path heading directly to the nearest passable navcell, then the goal. -
source/simulation2/helpers/Pathfinding.h
102 102 #define PASS_CLASS_MASK_FROM_INDEX(id) ((pass_class_t)(1u << id)) 103 103 #define SPECIAL_PASS_CLASS PASS_CLASS_MASK_FROM_INDEX(PASS_CLASS_BITS-1) // 16th bit, used for special in-place computations 104 104 105 typedef u64 CornerPassability; // 3 bits (see Pathfinding::PassableCorner) per passability class (up to PASS_CLASS_BITS) 106 105 107 namespace Pathfinding 106 108 { 107 109 /** … … 245 247 j += dj; 246 248 } 247 249 } 250 251 /** 252 * Corner passability values for a given passability class. Takes 3 bits. 253 * 254 * A cell can be passable but with an obstruction crossing it, so we 255 * have to determine one of the corners that is actually accessible. 256 */ 257 enum PassableCorner 258 { 259 ALL = 0x0, 260 NONE = 0x1, 261 TOP_LEFT = 0x2, 262 TOP_RIGHT = 0x3, 263 BOTTOM_LEFT = 0x4, 264 BOTTOM_RIGHT = 0x5 265 }; 266 267 inline void NavcellCorner(u16 i, u16 j, entity_pos_t& x, entity_pos_t& z, const PassableCorner& corner) 268 { 269 switch (corner) 270 { 271 case Pathfinding::ALL: 272 case Pathfinding::NONE: // this could happen when leaving an impassable 273 NavcellCenter(i, j, x, z); 274 return; 275 case Pathfinding::TOP_LEFT: 276 x = entity_pos_t::FromInt(i).Multiply(NAVCELL_SIZE); 277 z = entity_pos_t::FromInt(j).Multiply(NAVCELL_SIZE); 278 return; 279 case Pathfinding::TOP_RIGHT: 280 x = entity_pos_t::FromInt(i+1).Multiply(NAVCELL_SIZE); 281 z = entity_pos_t::FromInt(j).Multiply(NAVCELL_SIZE); 282 return; 283 case Pathfinding::BOTTOM_LEFT: 284 x = entity_pos_t::FromInt(i).Multiply(NAVCELL_SIZE); 285 z = entity_pos_t::FromInt(j+1).Multiply(NAVCELL_SIZE); 286 return; 287 case Pathfinding::BOTTOM_RIGHT: 288 x = entity_pos_t::FromInt(i+1).Multiply(NAVCELL_SIZE); 289 z = entity_pos_t::FromInt(j+1).Multiply(NAVCELL_SIZE); 290 return; 291 default: 292 LOGWARNING("Unknown corner passability"); 293 return; 294 } 295 } 296 297 inline PassableCorner GetPassableCorner(const CornerPassability& cornerPassability, pass_class_t passClass) 298 { 299 // Determine the bit position in the mask 300 ENSURE(passClass); 301 int i = 0; 302 while (!(passClass & (1u << i))) 303 ++i; 304 305 PassableCorner ret = static_cast<PassableCorner>((cornerPassability >> 3*i) & 0x7); 306 return ret; 307 } 308 309 inline void SetPassableCornerBits(CornerPassability& cornerPassability, const PassableCorner& passableCorner, pass_class_t mask) 310 { 311 // This function will be called by Rasterize so it has to support incremental overwritings: 312 // - ALL can only overwrite ALL (so it doesn't do anything) 313 // - single corner values can overwrite single corner values (consistent with the rasterization code) and ALL 314 // - NONE can overwrite anything 315 316 if (passableCorner == PassableCorner::ALL) 317 return; // nothing to actually do 318 319 for (int i = 0; i < PASS_CLASS_BITS; ++i) 320 { 321 if (!(mask & (0x1 << i))) 322 continue; 323 324 PassableCorner oldValue = static_cast<PassableCorner>((cornerPassability >> 3*i) & 0x7); 325 if (passableCorner != PassableCorner::NONE && oldValue == PassableCorner::NONE) 326 continue; // can't overwrite 327 328 cornerPassability &= (~(0x7 << 3*i)); // erase 329 cornerPassability |= passableCorner << 3*i; 330 } 331 } 332 333 // Apply @p mask onto both grids in adapted ways. 334 inline void CombinedGridsSet(Grid<NavcellData>& grid, Grid<CornerPassability>& cornerGrid, int i, int j, const PassableCorner& cornerValue, pass_class_t mask) 335 { 336 if (cornerValue == PassableCorner::NONE) 337 grid.set(i, j, grid.get(i, j) | mask); 338 339 CornerPassability cornerPassability = cornerGrid.get(i, j); 340 Pathfinding::SetPassableCornerBits(cornerPassability, cornerValue, mask); 341 cornerGrid.set(i, j, cornerPassability); 342 } 248 343 } 249 344 250 345 /* -
source/simulation2/helpers/Rasterize.cpp
41 41 42 42 for (i16 j = j0; j < j1; ++j) 43 43 { 44 // Find the min/max range of cells that are strictly inside the square+clearance. 45 // (Since the square+clearance is a convex shape, we can just test each 46 // corner of each cell is inside the shape.) 47 // (TODO: This potentially does a lot of redundant work.) 44 // Find the min/max range of cells that are inside the square+clearance. 45 // Since the square+clearance is a convex shape, we can just rely on corners for everything. 46 47 std::vector<Pathfinding::PassableCorner> corners; 48 corners.reserve(i1 - i0); 49 50 bool foundTouchingCell = false; 48 51 i16 spanI0 = std::numeric_limits<i16>::max(); 49 52 i16 spanI1 = std::numeric_limits<i16>::min(); 50 53 for (i16 i = i0; i < i1; ++i) 51 54 { 55 Pathfinding::PassableCorner corner = Pathfinding::PassableCorner::NONE; 56 int cornerCount = 0; 57 52 58 if (Geometry::DistanceToSquare( 53 59 CFixedVector2D(cellSize*i, cellSize*j) - CFixedVector2D(shape.x, shape.z), 54 60 shape.u, shape.v, CFixedVector2D(shape.hw, shape.hh), true) > clearance) 55 61 { 56 continue; 62 corner = Pathfinding::PassableCorner::TOP_LEFT; 63 ++cornerCount; 57 64 } 58 65 59 66 if (Geometry::DistanceToSquare( … … 60 67 CFixedVector2D(cellSize*(i+1), cellSize*j) - CFixedVector2D(shape.x, shape.z), 61 68 shape.u, shape.v, CFixedVector2D(shape.hw, shape.hh), true) > clearance) 62 69 { 63 continue; 70 corner = Pathfinding::PassableCorner::TOP_RIGHT; 71 ++cornerCount; 64 72 } 65 73 66 74 if (Geometry::DistanceToSquare( … … 67 75 CFixedVector2D(cellSize*i, cellSize*(j+1)) - CFixedVector2D(shape.x, shape.z), 68 76 shape.u, shape.v, CFixedVector2D(shape.hw, shape.hh), true) > clearance) 69 77 { 70 continue; 78 corner = Pathfinding::PassableCorner::BOTTOM_LEFT; 79 ++cornerCount; 71 80 } 72 81 73 82 if (Geometry::DistanceToSquare( … … 74 83 CFixedVector2D(cellSize*(i+1), cellSize*(j+1)) - CFixedVector2D(shape.x, shape.z), 75 84 shape.u, shape.v, CFixedVector2D(shape.hw, shape.hh), true) > clearance) 76 85 { 77 continue; 86 corner = Pathfinding::PassableCorner::BOTTOM_RIGHT; 87 ++cornerCount; 78 88 } 79 89 80 spanI0 = std::min(spanI0, i); 81 spanI1 = std::max(spanI1, (i16)(i+1)); 90 if (cornerCount == 4) 91 corner = Pathfinding::PassableCorner::ALL; 92 93 if (!foundTouchingCell) 94 { 95 if (corner == Pathfinding::PassableCorner::ALL) 96 continue; 97 98 foundTouchingCell = true; 99 spanI0 = i; 100 spanI1 = i+1; 101 corners.push_back(corner); 102 } 103 else 104 { 105 spanI1 = i+1; 106 corners.push_back(corner); 107 } 82 108 } 83 109 84 110 // Add non-empty spans onto the list 85 if ( spanI0 < spanI1)111 if (foundTouchingCell) 86 112 { 87 Span span = { spanI0, spanI1, j };88 spans. push_back(span);113 ENSURE(spanI0 < spanI1 && corners.size() == (size_t)(spanI1-spanI0)); 114 spans.emplace_back(Span{ spanI0, spanI1, j, corners }); 89 115 } 90 116 } 91 117 } -
source/simulation2/helpers/Rasterize.h
1 /* Copyright (C) 201 2Wildfire Games.1 /* Copyright (C) 2015 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 29 29 { 30 30 31 31 /** 32 * Represents the set of cells (i,j) where i0 <= i < i1 32 * Represents the set of cells (i,j) where i0 <= i < i1. 33 * The corner passability of the cell (i0+k,j) is corners[k]. 33 34 */ 34 35 struct Span 35 36 { … … 36 37 i16 i0; 37 38 i16 i1; 38 39 i16 j; 40 std::vector<Pathfinding::PassableCorner> corners; 39 41 }; 40 42 41 43 typedef std::vector<Span> Spans; … … 43 45 /** 44 46 * Converts an ObstructionSquare @p shape (a rotated rectangle), 45 47 * expanded by the given @p clearance, 46 * into a list of spans of cells that are strictly inside the shape. 48 * into a list of spans of cells that are at least partially inside the shape. 49 * The caller must check corner passability values for each cell inside a span 50 * to determine whether they are strictly inside the shape. 47 51 */ 48 52 void RasterizeRectWithClearance(Spans& spans, 49 53 const ICmpObstructionManager::ObstructionSquare& shape,