void rcMergeSpans( rcContext* ctx, rcHeightfield& solid ) { rcAssert( ctx ); ctx->startTimer( RC_TIMER_TEMPORARY ); const int w = solid.width; const int h = solid.height; for( int y = 0; y < h; ++y ) { for( int x = 0; x < w; ++x ) { for( rcSpan* s = solid.spans[x + y*w]; s != NULL && s->next != NULL; s = s->next ) { if( !rcIsSimilarTypeArea( s->area, s->next->area ) && rcAbs( static_cast<int>( s->next->smin ) - static_cast<int>( s->smax ) ) <= 2 ) { // merge rcSpan* next = s->next; s->smax = next->smax; const bool walkable = rcIsWalkableArea( s->area ) || rcIsWalkableArea( next->area ); s->area = next->area; s->area &= walkable ? ~RC_UNWALKABLE_AREA : ~RC_WALKABLE_AREA; s->area |= walkable ? RC_WALKABLE_AREA : RC_UNWALKABLE_AREA; s->next = next->next; freeSpan( solid, next ); } } } } ctx->stopTimer( RC_TIMER_TEMPORARY ); }
static bool addSpan(rcHeightfield& hf, const int x, const int y, const unsigned short smin, const unsigned short smax, const unsigned char area, const int flagMergeThr) { int idx = x + y*hf.width; rcSpan* s = allocSpan(hf); if (!s) return false; s->smin = smin; s->smax = smax; s->area = area; s->next = 0; // Empty cell, add the first span. if (!hf.spans[idx]) { hf.spans[idx] = s; return true; } rcSpan* prev = 0; rcSpan* cur = hf.spans[idx]; // Insert and merge spans. while (cur) { if (cur->smin > s->smax) { // Current span is further than the new span, break. break; } else if (cur->smax < s->smin) { // Current span is before the new span advance. prev = cur; cur = cur->next; } else { // Merge spans. if (cur->smin < s->smin) s->smin = cur->smin; if (cur->smax > s->smax) s->smax = cur->smax; // Merge flags. if (rcAbs((int)s->smax - (int)cur->smax) <= flagMergeThr) s->area = rcMax(s->area, cur->area); // Remove current span. rcSpan* next = cur->next; freeSpan(hf, cur); if (prev) prev->next = next; else hf.spans[idx] = next; cur = next; } } // Insert new span. if (prev) { s->next = prev->next; prev->next = s; } else { s->next = hf.spans[idx]; hf.spans[idx] = s; } return true; }