Ticket #930: ticket930-poc.patch
File ticket930-poc.patch, 10.0 KB (added by , 12 years ago) |
---|
-
source/simulation2/components/CCmpObstructionManager.cpp
250 250 UnitShape shape = { ent, x, z, r, flags, group }; 251 251 u32 id = m_UnitShapeNext++; 252 252 m_UnitShapes[id] = shape; 253 MakeDirtyUnit( flags);253 MakeDirtyUnit(shape); 254 254 255 255 m_UnitSubdivision.Add(id, CFixedVector2D(x - r, z - r), CFixedVector2D(x + r, z + r)); 256 256 … … 267 267 StaticShape shape = { ent, x, z, u, v, w/2, h/2, flags }; 268 268 u32 id = m_StaticShapeNext++; 269 269 m_StaticShapes[id] = shape; 270 MakeDirtyStatic( flags);270 MakeDirtyStatic(shape); 271 271 272 272 CFixedVector2D center(x, z); 273 273 CFixedVector2D bbHalfSize = Geometry::GetHalfBoundingBox(u, v, CFixedVector2D(w/2, h/2)); … … 312 312 shape.x = x; 313 313 shape.z = z; 314 314 315 MakeDirtyUnit(shape .flags);315 MakeDirtyUnit(shape); 316 316 } 317 317 else 318 318 { … … 336 336 shape.u = u; 337 337 shape.v = v; 338 338 339 MakeDirtyStatic(shape .flags);339 MakeDirtyStatic(shape); 340 340 } 341 341 } 342 342 … … 378 378 CFixedVector2D(shape.x - shape.r, shape.z - shape.r), 379 379 CFixedVector2D(shape.x + shape.r, shape.z + shape.r)); 380 380 381 MakeDirtyUnit(shape .flags);381 MakeDirtyUnit(shape); 382 382 m_UnitShapes.erase(TAG_TO_INDEX(tag)); 383 383 } 384 384 else … … 389 389 CFixedVector2D bbHalfSize = Geometry::GetHalfBoundingBox(shape.u, shape.v, CFixedVector2D(shape.hw, shape.hh)); 390 390 m_StaticSubdivision.Remove(TAG_TO_INDEX(tag), center - bbHalfSize, center + bbHalfSize); 391 391 392 MakeDirtyStatic(shape .flags);392 MakeDirtyStatic(shape); 393 393 m_StaticShapes.erase(TAG_TO_INDEX(tag)); 394 394 } 395 395 } … … 420 420 421 421 virtual bool Rasterise(Grid<u8>& grid); 422 422 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); 423 void GetShapesInRange(entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::map<u32, UnitShape>& outUnitShapes, std::map<u32, StaticShape>& outStaticShapes); 423 424 virtual bool FindMostImportantObstruction(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t r, ObstructionSquare& square); 424 425 425 426 virtual void SetPassabilityCircular(bool enabled) … … 444 445 // if a grid has a lower DirtyID then it needs to be updated. 445 446 446 447 size_t m_DirtyID; 448 entity_pos_t m_DirtyX0; 449 entity_pos_t m_DirtyZ0; 450 entity_pos_t m_DirtyX1; 451 entity_pos_t m_DirtyZ1; 452 // XXX: this probably breaks if used with multiple independently-dirtyable grids 447 453 448 454 /** 449 455 * Mark all previous Rasterise()d grids as dirty, and the debug display. … … 453 459 { 454 460 ++m_DirtyID; 455 461 m_DebugOverlayDirty = true; 462 m_DirtyX0 = m_WorldX0; 463 m_DirtyZ0 = m_WorldZ0; 464 m_DirtyX1 = m_WorldX1; 465 m_DirtyZ1 = m_WorldZ1; 456 466 } 457 467 458 468 /** … … 468 478 * Mark all previous Rasterise()d grids as dirty, if they depend on this shape. 469 479 * Call this when a static shape has changed. 470 480 */ 471 void MakeDirtyStatic( flags_t flags)481 void MakeDirtyStatic(const StaticShape& shape) 472 482 { 473 if (flags & (FLAG_BLOCK_PATHFINDING|FLAG_BLOCK_FOUNDATION)) 483 if (shape.flags & (FLAG_BLOCK_PATHFINDING|FLAG_BLOCK_FOUNDATION)) 484 { 474 485 ++m_DirtyID; 486 CFixedVector2D halfSize(shape.hw, shape.hh); 487 CFixedVector2D halfBound = Geometry::GetHalfBoundingBox(shape.u, shape.v, halfSize); 488 m_DirtyX0 = std::min(m_DirtyX0, shape.x - halfBound.X); 489 m_DirtyZ0 = std::min(m_DirtyZ0, shape.z - halfBound.Y); 490 m_DirtyX1 = std::max(m_DirtyX1, shape.x + halfBound.X); 491 m_DirtyZ1 = std::max(m_DirtyZ1, shape.z + halfBound.Y); 492 } 475 493 476 494 m_DebugOverlayDirty = true; 477 495 } … … 480 498 * Mark all previous Rasterise()d grids as dirty, if they depend on this shape. 481 499 * Call this when a unit shape has changed. 482 500 */ 483 void MakeDirtyUnit( flags_t flags)501 void MakeDirtyUnit(const UnitShape& shape) 484 502 { 485 if (flags & (FLAG_BLOCK_PATHFINDING|FLAG_BLOCK_FOUNDATION)) 503 if (shape.flags & (FLAG_BLOCK_PATHFINDING|FLAG_BLOCK_FOUNDATION)) 504 { 486 505 ++m_DirtyID; 506 entity_pos_t r = shape.r; 507 m_DirtyX0 = std::min(m_DirtyX0, shape.x - r); 508 m_DirtyZ0 = std::min(m_DirtyZ0, shape.z - r); 509 m_DirtyX1 = std::max(m_DirtyX1, shape.x + r); 510 m_DirtyZ1 = std::max(m_DirtyZ1, shape.z + r); 511 } 487 512 488 513 m_DebugOverlayDirty = true; 489 514 } … … 708 733 if (!IsDirty(grid)) 709 734 return false; 710 735 711 PROFILE("Rasterise"); 736 PROFILE3("Rasterise"); 737 TIMER(L"Rasterise"); 712 738 713 739 grid.m_DirtyID = m_DirtyID; 714 740 … … 716 742 // What we should perhaps do is have some kind of quadtree storing Shapes so it's 717 743 // quick to invalidate and update small numbers of tiles 718 744 719 grid.reset();745 // grid.reset(); 720 746 721 747 // For tile-based pathfinding: 722 748 // Since we only count tiles whose centers are inside the square, … … 733 759 // so we need to expand by at least 1/sqrt(2) of a tile 734 760 entity_pos_t expandFoundation = (entity_pos_t::FromInt(CELL_SIZE) * 3) / 4; 735 761 736 for (std::map<u32, StaticShape>::iterator it = m_StaticShapes.begin(); it != m_StaticShapes.end(); ++it) 762 763 // debug_printf(L"# Rasterising region %f %f %f %f\n", m_DirtyX0.ToFloat(), m_DirtyZ0.ToFloat(), m_DirtyX1.ToFloat(), m_DirtyZ1.ToFloat()); 764 765 // XXX: if it's a large region (e.g. the whole map changed), we should just 766 // reset the entire grid and redraw every shape, instead of doing GetShapesInRange etc 767 768 // XXX: we should do a fancier dirty-rectangles, so if there were two small changes 769 // on opposite sides of the map we won't have to re-rasterise all the tiles in between 770 771 u16 dirtyI0, dirtyJ0, dirtyI1, dirtyJ1; 772 entity_pos_t dirtyExpand = std::max(expandPathfinding, expandFoundation) * 2; // expand by hopefully enough to avoid missing some edges (XXX: this might not be right) 773 NearestTile(m_DirtyX0 - dirtyExpand, m_DirtyZ0 - dirtyExpand, dirtyI0, dirtyJ0, grid.m_W, grid.m_H); 774 NearestTile(m_DirtyX1 + dirtyExpand, m_DirtyZ1 + dirtyExpand, dirtyI1, dirtyJ1, grid.m_W, grid.m_H); 775 776 grid.reset(dirtyI0, dirtyJ0, dirtyI1, dirtyJ1); 777 778 std::map<u32, StaticShape> staticShapes; 779 std::map<u32, UnitShape> unitShapes; 780 GetShapesInRange(m_DirtyX0 - dirtyExpand*2, m_DirtyZ0 - dirtyExpand*2, m_DirtyX1 + dirtyExpand*2, m_DirtyZ1 + dirtyExpand*2, unitShapes, staticShapes); 781 // XXX: should make GetShapesInRange only return shapes with the appropriate flags 782 // XXX: to minimise memory allocation, should return shape lists as std::vector<u32> 783 // instead of creating a std::map and copying the actual shape structs. 784 // Or we could just use m_StaticSubdivision.GetInRange directly here. 785 786 // Reset dirty region to empty 787 m_DirtyX0 = m_WorldX1; 788 m_DirtyZ0 = m_WorldZ1; 789 m_DirtyX1 = m_WorldX0; 790 m_DirtyZ1 = m_WorldZ0; 791 792 for (std::map<u32, StaticShape>::iterator it = staticShapes.begin(); it != staticShapes.end(); ++it) 737 793 { 738 794 CFixedVector2D center(it->second.x, it->second.z); 739 795 … … 778 834 } 779 835 } 780 836 781 for (std::map<u32, UnitShape>::iterator it = m_UnitShapes.begin(); it != m_UnitShapes.end(); ++it)837 for (std::map<u32, UnitShape>::iterator it = unitShapes.begin(); it != unitShapes.end(); ++it) 782 838 { 783 839 CFixedVector2D center(it->second.x, it->second.z); 784 840 … … 816 872 817 873 if (m_PassabilityCircular) 818 874 { 819 for (u16 j = 0; j < grid.m_H; ++j)875 for (u16 j = dirtyJ0; j < dirtyJ1; ++j) 820 876 { 821 for (u16 i = 0; i < grid.m_W; ++i)877 for (u16 i = dirtyI0; i < dirtyI1; ++i) 822 878 { 823 879 // Based on CCmpRangeManager::LosIsOffWorld 824 880 // but tweaked since it's tile-based instead. … … 840 896 NearestTile(m_WorldX0, m_WorldZ0, i0, j0, grid.m_W, grid.m_H); 841 897 NearestTile(m_WorldX1, m_WorldZ1, i1, j1, grid.m_W, grid.m_H); 842 898 899 // XXX: use dirty region 843 900 for (u16 j = 0; j < grid.m_H; ++j) 844 901 for (u16 i = 0; i < i0+edgeSize; ++i) 845 902 grid.set(i, j, edgeFlags); … … 906 963 } 907 964 } 908 965 966 void CCmpObstructionManager::GetShapesInRange(entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::map<u32, UnitShape>& outUnitShapes, std::map<u32, StaticShape>& outStaticShapes) 967 { 968 ENSURE(x0 <= x1 && z0 <= z1); 969 970 std::vector<u32> unitShapes = m_UnitSubdivision.GetInRange(CFixedVector2D(x0, z0), CFixedVector2D(x1, z1)); 971 for (size_t i = 0; i < unitShapes.size(); ++i) 972 { 973 std::map<u32, UnitShape>::iterator it = m_UnitShapes.find(unitShapes[i]); 974 ENSURE(it != m_UnitShapes.end()); 975 976 entity_pos_t r = it->second.r; 977 978 // Skip this object if it's completely outside the requested range 979 if (it->second.x + r < x0 || it->second.x - r > x1 || it->second.z + r < z0 || it->second.z - r > z1) 980 continue; 981 982 outUnitShapes.insert(*it); 983 } 984 985 std::vector<u32> staticShapes = m_StaticSubdivision.GetInRange(CFixedVector2D(x0, z0), CFixedVector2D(x1, z1)); 986 for (size_t i = 0; i < staticShapes.size(); ++i) 987 { 988 std::map<u32, StaticShape>::iterator it = m_StaticShapes.find(staticShapes[i]); 989 ENSURE(it != m_StaticShapes.end()); 990 991 entity_pos_t r = it->second.hw + it->second.hh; // overestimate the max dist of an edge from the center 992 993 // Skip this object if its overestimated bounding box is completely outside the requested range 994 if (it->second.x + r < x0 || it->second.x - r > x1 || it->second.z + r < z0 || it->second.z - r > z1) 995 continue; 996 997 outStaticShapes.insert(*it); 998 } 999 } 1000 909 1001 bool CCmpObstructionManager::FindMostImportantObstruction(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t r, ObstructionSquare& square) 910 1002 { 911 1003 std::vector<ObstructionSquare> squares; -
source/simulation2/helpers/Grid.h
80 80 memset(m_Data, 0, m_W*m_H*sizeof(T)); 81 81 } 82 82 83 // Reset all tiles i0 <= i <= i1, j0 <= j <= j1 84 void reset(int i0, int j0, int i1, int j1) 85 { 86 ENSURE(0 <= i0 && i0 < m_W && 0 <= i1 && i1 < m_W && 0 <= j0 && j0 < m_H && 0 <= j1 && j1 < m_H); 87 for (int j = j0; j <= j1; ++j) 88 for (int i = i0; i <= i1; ++i) 89 m_Data[j*m_W + i] = 0; 90 } 91 83 92 void set(int i, int j, const T& value) 84 93 { 85 94 #if GRID_BOUNDS_DEBUG