I am trying to make a 2D game engine using OpenGL ES 2.0 (iOS for now). I\'ve written Application layer in Objective C and a separate self contained RendererGLES20 in C++. No GL
The whole point of shaders is to be specific. Generic APIs and inflation of the state machine poisoned OpenGL for a long time (just look at the OpenGL-1.5 glTexEnv). The whole point of modern OpenGL (v3 and beyond) was to get rid of this genericity, so that shaders could be tailored for the task at hand with easy. Don't think shaders to be something separate from the renderer code that uses them. In fact shaders and client side renderer code are complementary and are usually developed in unison.
When no attributes or uniforms change then you can change the shader without having to recompile your c++ code. You do this by either loading you shader code from a text file with glShaderSource
and then compiling it, or by loading a precompiled binary file with glShaderBinary
.
To get some sort of encapsulation of the different rendering methods you can have different renderers that inherit from RendererGLES20. That way only the renderer needs to know what attributes and uniforms the shader needs.
class RendererGLES20
{
public:
virtual void render(Model * model) = 0;
// ...
}
class RippleRenderer : public RendererGLES20
{
virtual void render(Model * model);
// ...
}
class BlinnPhongRenderer : public RendererGLES20
{
virtual void render(Model * model);
// ...
}
class CartoonRenderer : public RendererGLES20
{
virtual void render(Model * model);
// ...
}
As datenwolf says, shaders are not supposed to be generic.
That said, in theory, you can just swap out shaders code as you wish, as long as it uses all the same uniform
, in
and out
parameters nothing will really be able to tell the difference. That said, this is probably not a good idea at all.
If you want such flexibility, you probably want to look at introducing some sort intermediary scripting layer. Your engine can provide this scripting layer all the information you want it to, and the script layer can take care of working out what uniforms to set and what to set them to. It is not a trivial thing do, but then what you are trying to do is not exactly easy.
I'm not claiming to be an expert (I'm in the exact same stage of learning to use OpenGL as you) but here is what I would try:
Maybe you can make an abstract RenderEffect class and pass a (list of) of these to RendererGLES20::render(). From it you would derive classes such as RippleEffect and BloomEffect. A RenderEffect object would contain all the information your renderer needs to make the necessary ogl state adjustments specific to your shader. It would essentially be a container class of:
Derived classes can declare a constructor with arguments that match the info needed for that specific effect and would store it in the lists defined by their parent class. So the constructor of RippleEffect might have parameters for delta t and diameter and when it is called it creates and stores a UniformInfo object for each.
Finally, you can make all of this data-driven and specify all of the info in a text file. That would be just one step short of creating a scripting-system like thecoshman proposed.
PS: UniformInfo objects and VertexAttribInfo objects would store or reference values of different types. To deal with this you could make different classes for each type but I recommend storing just a void* or the likes. Another option is using templates but I don't know anything about objective-c so I don't know if that is possible.