Creating an STL "Render Stream"

Started by
5 comments, last by brwarner 15 years, 5 months ago
Hi, I am making a game engine that uses DirectX and I thought it might be a cool experiment to try and create an STL "Render Stream". This stream would allow the render function to look something like this:

//Render function
CRenderStream rout = pRenderDevice->GetStream();
rout << SomeArrayOfVerticies << AnotherArrayOfVerticies << ANewWorldMatrix
       << AMeshObject << SomeVerticies;


Now I have looked at both the STL streams and the Boost IOStream library but both of them seem to only really allow for char/wchar_t input. I could simply create a class that overrides those operators but it would be nice to derive from an STL class just so it could be interfaced easily with STL algorithms. So, how can I do this with either inheriting from an STL class or using the Boost IOStream library? Final Note: Please in no response say that this is a bad idea or something. I just want to know how to do it and want to experiment with it so don't post if you are not going to be helpful to that cause.
Advertisement
Basic idea:
struct RenderStream {  void append(const Mesh & m);  void append(const Matrix & m);  void append(const Vertices & m);};template < class T >RenderStream & opearator<<(RenderStream & rs, const T & t) {  rs.append(t);  return rs;}


Although the usefulness of this is beyond me. There's not really much that algorithms or such would add to this either.
Quote:Original post by brwarner
I could simply create a class that overrides those operators but it would be nice to derive from an STL class just so it could be interfaced easily with STL algorithms.

Both STL and Boost are heavily templatized. You don't need to inherit from these classes in order to make them cooperate with STL algorithms, you simply need to provide the required 'interface' (for example, some containers require objects to have a copy constructor and assignment operator, some algorithms want a comparison operator, etc). I do wonder though, what algorithms would need to operate on your render stream? Does your render stream actually behave like a stream, so it makes sense to use those algorithms?


Anyway, just overload the << operator for the types you need and you should be fine. Although it's probably better to use functions with proper names. With operators, you should strive to provide the functionality that people expect, or you'll confuse them (including yourself, eventually).

Take a look at this:
renderStream << model1 << matrix2 << model3 << matrix4 << model5;

versus this:
renderStream.DrawModel(model1).PushMatrix(matrix2).DrawModel(model3).PopMatrix();

I think you'll agree that while the second approach takes a little more typing, it's also much more clear and flexible. How are you going to pop a matrix with only operator <<?
Create-ivity - a game development blog Mouseover for more information.
Quote:There's not really much that algorithms or such would add to this either.
A rendering monad would be a little more useful WRT composing and culling render ops.
This is fine if you're doing it as a learning exercise, but something like this is pretty evil

Adding syntactic sugar for the sake of it, rather than when it makes sense, is always a bad idea.

rout << SomeArrayOfVerticies << AnotherArrayOfVerticies << ANewWorldMatrix       << AMeshObject << SomeVerticies;


Looking at this code, I have absolutely no idea what it's supposed to do. Obviously I can hazard a guess, but it's not 100% clear what's supposed to be going on here. I'd be pretty pissed off if I had to maintain code like this.

If you're dead set on this, don't derive from an existing STL class. The classes aren't designed to be inherited from. STL uses templates to allow code to be used with more than one container type, the STL classes don't inherit from a common base class.

Look at the functions in <algorithm> for an example of what I'm talking about (std::for_each, for example).
As Sneftel briefly touched on, this method would make it a real PITA to cull out render ops (you'd have to write some nasty interfaces underneath this stream, at which point maintenance would be *fun*). Also, the only real way you could implement a scene graph would be to support the serialization of sub-RenderStream objects into a main RenderStream. That way, you could push parent level world state and then stream in sub-streams afterwards which do not need to individually push world state for local-to-world transforms, etc. A very powerful feature of a next-gen renderer is to be multi-threaded, away from the game code. This method (with immediate dispatch) would not work. Instead, you want to design a system that can queue up a stream of commands to be executed at a later time. Then when running single threaded, you can then immediately dispatch the command buffer, but when runining multi-threaded, you could dispatch the command buffer on the next frame on a different thread.

I agree that as a learning exercise, what you proposed could be useful. You generally wouldn't see this pattern in a high-performing next-gen renderer; the rendering overhead and lack of smart caching would hurt what you could push through the renderer.

Hopefully my winded blabbering made sense; I'm tired :)

~Graham
Thanks for all the responses, and I now have some good ideas why it would not work so well, I just thought it might be a cool idea to have an STL style Render Engine. Thanks for all the feedback and based on your arguments I will probably not use this idea.

This topic is closed to new replies.

Advertisement