-
Notifications
You must be signed in to change notification settings - Fork 0
Improve hot-paths for openMW #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,13 +17,22 @@ | |
| // | ||
|
|
||
| #include "Recast.h" | ||
| #include "RecastAlloc.h" | ||
| #include "RecastAssert.h" | ||
|
|
||
| #include <stdlib.h> | ||
|
|
||
| namespace | ||
| { | ||
| const int MAX_HEIGHTFIELD_HEIGHT = 0xffff; // TODO (graham): Move this to a more visible constant and update usages. | ||
|
|
||
| struct FilterSpan | ||
| { | ||
| rcSpan* source; | ||
| unsigned short smin; | ||
| unsigned short smax; | ||
| unsigned char area; | ||
| }; | ||
| } | ||
|
|
||
| void rcFilterLowHangingWalkableObstacles(rcContext* context, const int walkableClimb, rcHeightfield& heightfield) | ||
|
|
@@ -72,49 +81,101 @@ void rcFilterLedgeSpans(rcContext* context, const int walkableHeight, const int | |
|
|
||
| const int xSize = heightfield.width; | ||
| const int zSize = heightfield.height; | ||
| const int columnCount = xSize * zSize; | ||
|
|
||
| // Ledge filtering repeatedly scans the four neighbouring columns for every | ||
| // span. Flatten the linked lists once so those scans read contiguous data. | ||
| rcTempVector<int> columnOffsets(columnCount + 1, 0); | ||
| int spanCount = 0; | ||
| for (int columnIndex = 0; columnIndex < columnCount; ++columnIndex) | ||
| { | ||
| columnOffsets[columnIndex] = spanCount; | ||
| for (const rcSpan* span = heightfield.spans[columnIndex]; span != NULL; span = span->next) | ||
| { | ||
| ++spanCount; | ||
| } | ||
| } | ||
| columnOffsets[columnCount] = spanCount; | ||
|
|
||
| rcTempVector<FilterSpan> spans(spanCount); | ||
| int spanIndex = 0; | ||
| for (int columnIndex = 0; columnIndex < columnCount; ++columnIndex) | ||
| { | ||
| for (rcSpan* span = heightfield.spans[columnIndex]; span != NULL; span = span->next) | ||
| { | ||
| FilterSpan& filterSpan = spans[spanIndex++]; | ||
| filterSpan.source = span; | ||
| filterSpan.smin = (unsigned short)span->smin; | ||
| filterSpan.smax = (unsigned short)span->smax; | ||
| filterSpan.area = (unsigned char)span->area; | ||
| } | ||
| } | ||
|
|
||
| // Mark spans that are adjacent to a ledge as unwalkable.. | ||
| for (int z = 0; z < zSize; ++z) | ||
| { | ||
| for (int x = 0; x < xSize; ++x) | ||
| { | ||
| for (rcSpan* span = heightfield.spans[x + z * xSize]; span; span = span->next) | ||
| const int columnIndex = x + z * xSize; | ||
| const int columnEnd = columnOffsets[columnIndex + 1]; | ||
| int neighborColumnStarts[4]; | ||
| int neighborColumnEnds[4]; | ||
| int firstHigherNeighborCeilings[4]; | ||
| for (int direction = 0; direction < 4; ++direction) | ||
| { | ||
| const int neighborX = x + rcGetDirOffsetX(direction); | ||
| const int neighborZ = z + rcGetDirOffsetY(direction); | ||
| if (neighborX < 0 || neighborZ < 0 || neighborX >= xSize || neighborZ >= zSize) | ||
| { | ||
| neighborColumnStarts[direction] = -1; | ||
| neighborColumnEnds[direction] = -1; | ||
| firstHigherNeighborCeilings[direction] = -1; | ||
| continue; | ||
| } | ||
|
|
||
| const int neighborColumnIndex = neighborX + neighborZ * xSize; | ||
| neighborColumnStarts[direction] = columnOffsets[neighborColumnIndex]; | ||
| neighborColumnEnds[direction] = columnOffsets[neighborColumnIndex + 1]; | ||
| firstHigherNeighborCeilings[direction] = neighborColumnStarts[direction] + 1; | ||
| } | ||
| for (int currentSpanIndex = columnOffsets[columnIndex]; currentSpanIndex < columnEnd; ++currentSpanIndex) | ||
| { | ||
| FilterSpan& span = spans[currentSpanIndex]; | ||
| // Skip non-walkable spans. | ||
| if (span->area == RC_NULL_AREA) | ||
| if (span.area == RC_NULL_AREA) | ||
| { | ||
| continue; | ||
| } | ||
|
|
||
| const int floor = (int)(span->smax); | ||
| const int ceiling = span->next ? (int)(span->next->smin) : MAX_HEIGHTFIELD_HEIGHT; | ||
| const int floor = (int)(span.smax); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Even though this code pretty much looks like C it's C++ and it has |
||
| const int ceiling = currentSpanIndex + 1 < columnEnd | ||
| ? (int)(spans[currentSpanIndex + 1].smin) : MAX_HEIGHTFIELD_HEIGHT; | ||
|
|
||
| // The difference between this walkable area and the lowest neighbor walkable area. | ||
| // This is the difference between the current span and all neighbor spans that have | ||
| // enough space for an agent to move between, but not accounting at all for surface slope. | ||
| int lowestNeighborFloorDifference = MAX_HEIGHTFIELD_HEIGHT; | ||
|
|
||
| // Min and max height of accessible neighbours. | ||
| int lowestTraversableNeighborFloor = span->smax; | ||
| int highestTraversableNeighborFloor = span->smax; | ||
| int lowestTraversableNeighborFloor = span.smax; | ||
| int highestTraversableNeighborFloor = span.smax; | ||
|
|
||
| for (int direction = 0; direction < 4; ++direction) | ||
| { | ||
| const int neighborX = x + rcGetDirOffsetX(direction); | ||
| const int neighborZ = z + rcGetDirOffsetY(direction); | ||
|
|
||
| // Skip neighbours which are out of bounds. | ||
| if (neighborX < 0 || neighborZ < 0 || neighborX >= xSize || neighborZ >= zSize) | ||
| if (neighborColumnStarts[direction] < 0) | ||
| { | ||
| lowestNeighborFloorDifference = -walkableClimb - 1; | ||
| break; | ||
| } | ||
|
|
||
| const rcSpan* neighborSpan = heightfield.spans[neighborX + neighborZ * xSize]; | ||
| int neighborSpanIndex = neighborColumnStarts[direction]; | ||
| const int neighborColumnEnd = neighborColumnEnds[direction]; | ||
|
|
||
| // The most we can step down to the neighbor is the walkableClimb distance. | ||
| // Start with the area under the neighbor span | ||
| int neighborCeiling = neighborSpan ? (int)neighborSpan->smin : MAX_HEIGHTFIELD_HEIGHT; | ||
| int neighborCeiling = neighborSpanIndex < neighborColumnEnd | ||
| ? (int)spans[neighborSpanIndex].smin : MAX_HEIGHTFIELD_HEIGHT; | ||
|
|
||
| // Skip neighbour if the gap between the spans is too small. | ||
| if (rcMin(ceiling, neighborCeiling) - floor > walkableHeight) | ||
|
|
@@ -123,11 +184,32 @@ void rcFilterLedgeSpans(rcContext* context, const int walkableHeight, const int | |
| break; | ||
| } | ||
|
|
||
| // Spans are sorted by height. Any neighbour whose next ceiling is at or below | ||
| // floor + walkableHeight will take the overlap test's continue branch below. | ||
| // Seek past that prefix instead of rescanning it for every higher span. | ||
| const int minNeighborCeiling = floor + walkableHeight; | ||
| if (ceiling <= minNeighborCeiling) | ||
| { | ||
| continue; | ||
| } | ||
| int& firstHigherCeiling = firstHigherNeighborCeilings[direction]; | ||
| while (firstHigherCeiling < neighborColumnEnd | ||
| && (int)spans[firstHigherCeiling].smin <= minNeighborCeiling) | ||
| { | ||
| ++firstHigherCeiling; | ||
| } | ||
| neighborSpanIndex = firstHigherCeiling - 1; | ||
|
|
||
| // For each span in the neighboring column... | ||
| for (; neighborSpan != NULL; neighborSpan = neighborSpan->next) | ||
| for (; neighborSpanIndex < neighborColumnEnd; ++neighborSpanIndex) | ||
| { | ||
| const int neighborFloor = (int)neighborSpan->smax; | ||
| neighborCeiling = neighborSpan->next ? (int)neighborSpan->next->smin : MAX_HEIGHTFIELD_HEIGHT; | ||
| const int neighborFloor = (int)spans[neighborSpanIndex].smax; | ||
| if (neighborFloor + walkableHeight >= ceiling) | ||
| { | ||
| break; | ||
| } | ||
| neighborCeiling = neighborSpanIndex + 1 < neighborColumnEnd | ||
| ? (int)spans[neighborSpanIndex + 1].smin : MAX_HEIGHTFIELD_HEIGHT; | ||
|
|
||
| // Only consider neighboring areas that have enough overlap to be potentially traversable. | ||
| if (rcMin(ceiling, neighborCeiling) - rcMax(floor, neighborFloor) <= walkableHeight) | ||
|
|
@@ -161,12 +243,14 @@ void rcFilterLedgeSpans(rcContext* context, const int walkableHeight, const int | |
| // the magnitude of the delta) | ||
| if (lowestNeighborFloorDifference < -walkableClimb) | ||
| { | ||
| span->area = RC_NULL_AREA; | ||
| span.area = RC_NULL_AREA; | ||
| span.source->area = RC_NULL_AREA; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this is the only use case for source. |
||
| } | ||
| // If the difference between all neighbor floors is too large, this is a steep slope, so mark the span as an unwalkable ledge. | ||
| else if (highestTraversableNeighborFloor - lowestTraversableNeighborFloor > walkableClimb) | ||
| { | ||
| span->area = RC_NULL_AREA; | ||
| span.area = RC_NULL_AREA; | ||
| span.source->area = RC_NULL_AREA; | ||
| } | ||
| } | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this used?