I have a sorted array of objects (sorted back to front*), and I want to reorder them (to reduce videocard state changes), but they have dependencies (I can't reorder one object to be infront of an object that is supposed to cover it).
*2D graphics, lots of alpha, no depth buffer.
After sorting back to front, the dependencies are met, but it's far from optimal - there is room to re-arrange the draw calls to reduce state changes further.
So instead I'd sort by:
bool ShouldDrawBefore(const Object &objectA, const Object &objectB)
{
if(objectA.coveredBy(objectB))
return true;
return (objectA.renderState < objectB.renderState);
}
That'll ensure the dependencies are met, and also group similar renderstates. This is better, but not quite there.
Imagine that I'm drawing a bunch of rocks, then one rock is occluded by a tree. If the rock renderstate is "less than" the tree renderstate, that means it'd go:
rock rock rock rock rock
tree //occluding tree
rock rock rock
tree tree tree tree
Instead, I'd rather once it switches to 'tree' that it tries to draw every tree that it can, before it switches back to rock.
rock rock rock rock rock
tree tree tree tree tree
rock rock rock
I'm trying to figure out how I'd do that - I'm fine making more than one sorting pass.
(there's much more than just two render states, but two is enough to demonstrate the problem)
Conceptually, I want something like this
bool ShouldDrawBefore(const Object &objectA, const Object &objectB)
{
if(objectA.coveredBy(objectB))
return true;
//If we can avoid changing states, do so.
//'previousRenderState' would be a lambda capture or functor member-var.
if(objectB.renderState == previousRenderState)
return false;
return (objectA.renderState < objectB.renderState);
}
While conceptually that'd work, in practice, many sort algorithms visit the elements of array in a arbitrary order, so 'previousRenderState' wouldn't be accurate until after the sort is complete.
Any suggestions for how I should go about sorting these?