pioneerspacesim/pioneer — Issue #913: Renderer
Author: Luomu
Created: 2012-01-23 16:39:32+00:00
State: open

Branch here, explore the commits: https://github.com/Luomu/pioneer/tree/renderer

Comments & design help welcome, there's still a lot to be done

**Goals:**
make it possible to port to OpenGL ES2 (or even DirectX if someone wants to) without going crazy
get rid of immediate mode drawing
remove and reduce opengl calls in general source code - glEverything()
reduce code duplication (there are only so many ways you want to draw a quad) ((recurring cases should be primarily wrapped in methdods like FillRect before calling the renderer directly))

The current class definition is short enough to be pasted here (extra comments with XX):

```
// Renderer base, functions return false if
// failed/unsupported
class Renderer
{
public:
Renderer(int width, int height);
virtual ~Renderer();

virtual const char* GetName() = 0;

virtual bool BeginFrame() = 0;
virtual bool EndFrame() = 0;
//traditionally gui happens between endframe and swapbuffers
virtual bool SwapBuffers() = 0;

//render state functions
//XX expand whenever sensible but this should be enough to demonstrate the idea
virtual bool SetBlendMode(BlendMode type) { return false; }
//virtual bool SetState(DEPTH_TEST, false) or
//virtual bool SetDepthTest(false) ?

//XX obvious stuff like SetViewport will be added

virtual bool SetLights(int numlights, const Light *l) { return false; }
virtual bool SetAmbientColor(const Color &c) { return false; }

//drawing functions
//2d drawing is generally understood to be for gui use (unlit, ortho projection)
//XX here I was still using specialized data structures
//XX could also be an array of vector3fs and array of Colors - let me know if you care
virtual bool DrawLines(int vertCount, const LineVertex *vertices, LineType type=LINE_SINGLE) { return false; }
virtual bool DrawLines2D(int vertCount, const LineVertex2D *vertices, LineType type=LINE_SINGLE) { return false; }
//unindexed triangle draw
//XX here I started using a generic VertexArray because there are too many attribute combinations
virtual bool DrawTriangles(const VertexArray *vertices, const Material *material=0, PrimitiveType type=TRIANGLES) { return false; }
virtual bool DrawTriangles2D(const VertexArray *vertices, const Material *material=0, PrimitiveType type=TRIANGLES) { return false; }
//indexed triangle draw
virtual bool DrawSurface(const Surface *surface) { return false; }
virtual bool DrawSurface2D(const Surface *surface) { return false; }

//virtual bool DrawPoints(...)
//virtual bool DrawPointSprites(...) //high amount of textured quads for particles etc

//XX for complex geometry - the data will be processed & cached into something the renderer prefers
virtual bool DrawBufferThing(BufferThing *thing) { return false; }

protected:
int m_width;
int m_height;
};
```

**Core concepts**
VertexArray: at first I used specialized data structures like ColoredVertex (see DrawLines for this style) but there are too many possible combinations of attributes.
Material: holds info on, well, material properties. And textures.
Surface: has one vertex array, one index array (for indexed triangle drawing) and a material.
BufferThing: Complex, static geometry that is expected to be buffered. Can have multiple surfaces. This is not fully fleshed out and I ran out of names here :) Mesh? Solid? Model? See background for example use.

**Renderer choice**
I have started two renderers (quickly put together - will be rewritten). RendererLegacy is the fixed-function AKA shaderless one. We can keep it around as long as someone wants to maintain it. RendererGL2 is the new OpenGL 2.0 or 2.1 one that aims to shed as much historical baggage as possible. From a player's point of view it will not be possible to swap between these without restarting (not impossible but I wouldn't bother).

**Materials & Shaders**
It is desirable to let the renderer choose and manage the appropriate shaders, for example when drawing unlit 2D lines the GL2 renderer is expected to choose simpleShader or similar. If textures are needed, that can be determined using a Material.
It's not always straightforward, for example with the planet atmosphere it's not enouch to communicate the choice of shader but also a bunch of uniforms.
Perhaps something called "Effect" that can store the appropriate parameters?
See Planet.cpp and rings drawing how this is shaping up.

**Unknown territory**
LMRModel is such a big blob of stuff I don't know how easy it is to make play nice with Renderer. I would like to add a model base class separate from LMRModel anyway.
Terrain is another special case. I'd expect to add something like DrawTerrain(Patch *p) that works somewhat like DrawBufferThing.
SDL or not, Would be nice if the Renderer could also create the context.

**Transformations**
the classic matrix stack (pushMatrix, popMatrix) we rely on everywhere needs to be replaced somehow.
Also, projections. Renderer will have SetProjection or SetCamera type stuff.

**Render.cpp** - this will be slowly erased. Post processing needs to go somewhere else. I have a branch related to this (see http://github.com/Luomu/pioneer/blob/filters/src/render/RenderPostControl.cpp) but it needs to be reconsidered wrt. Renderer.