Ok, the task of batch rendering can roughly be broken up into two parts, the sorting and the actual rendering. Because we have to sort, I don't think there's any way around having some kind of container that you queue drawables into each frame. I think you'd almost certainly want to add some kind of layer variable to drawables. Then sorting would be something like layer/[view]/topology/image/blend mode (topology might be better last, it depends).
From there I see two possibilities. The first is to have the drawables give the data necessary to the renderer.
void BatchRenderer::render()
{
sort queue
for each drawable in queue
get drawable render information
draw the stuff
empty the queue
}
I could see this being made potentially fairly fast, but it's probably harder to extend. If you needed some new topology or something, you'd have to add it to the render function.
The second strategy (which I think probably fits SFML best) would be to add a new virtual member function on drawables (private and friends with the batchrenderer). Then create a class BatchRenderState (my nomenclature shouldn't be taken as recommended, just using whatever comes to mind) that holds the current state and the batched data.
That would look something like this:
void BatchRenderer::render
{
sort queue
for each renderable in queue
drawable->batchrender ( batchrenderstate );
batchrenderstate.finished
empty the queue
}
A drawable batchrender function would then look something like this:
void SomeDrawable::batchrender ( batchrenderstate )
{
batchrenderstate.setstate ( drawable's topology, image, etc. );
batchrenderstate.setdata ( drawable's vertices, texture coords, etc. )
}
The batchrenderstate object would watch for state changes, thus ending the current batch and would actually call opengl with whatever it had stored up so far. If things were written well, you could even call opengl inside the drawable::batchrender without passing the data to the state object, as long as you informed the state object accordingly (a flush type command, or set state without data).
I think a few things could be problematic, namely child drawables (since you can't push/pop and have a good batch renderer), the current color, the view (you have to queue everything, so if you have different views that has to go in there as well). For views, one solution is to have per layer views, so the renderer can change the view when the layer changes. That might work for colors as well (colorable layers vs normal layers). Heh, you could even do blend modes that way to avoid having to check lots of state with each drawable.
There are some potential speed optimizations as well, for example, maybe instead of setdata, it's getdataptr and then the drawable stuffs the data in itself. *shrug*
Anyway, a proposal at least. =) Now that I've thought it out, it's less complicated than I expected.