I'm developing a little game engine for Android with Android NDK and opengl es 2.0, recently the project is getting big, and I need to refactor some code, and I couldn't find a proper design pattern for the next problem.
On android when the app reach the OnPause() state the opengl context is destroyed, but the state of the variables and objects in java and c++ are maintained. so each time the player pauses and resumes the app I have to reinitializate the opengl part, buffers, shaders, vertex, etc.
I have classes like "Square" that makes "square objects", and each one has its own attributes, and each "square object" can be drawn, so the squares can access to static (opengl) members of the class, that are used to be properly rendered. So this static members must be initialized before objects can be drawn, I do it when the opengl context is created or recreated.
moreover each class has its own opengl attributes, so each class is initialized individually with its own parameters, so I want a design in what each class can set some initial parameters, pass or catch those parameters to initialize the static members of the class (I forgot to say that these parameters are private). But as I said before, these parameters need to be reinitialized each time the app is resumed.
currently I initialize these members individually like
Square::init(/*hardcoded parameters*/);
Circle::init(/*hardcoded parameters*/);
Triangle::init(/*hardcoded parameters*/);
Polygon::init(/*hardcoded parameters*/);
Shape::init(/*hardcoded parameters*/);
.
.
.
.
// Many other inits.....
.
and I want to write something like
// here all the classes with opengl part are initialized
// all init methods of each class are called here, with their respective parameters
Opengl_Initializer::init(); // <--- magic way, no other init calls
So I want to set some (static/harcoded) variables to the class and then when the opengl context be created, the class be initialized in a "magic" way, and not having the need to code the call to an init method for each class.
I've tried to use inheritance, but the issue is that I need to initialize the class not the object, also tried to implement a static object and initialize this object in the cpp file, and store a pointer to the object in a vector when this is created in his contructor, in a vector that is in the object's own class, but this design has gave me many problems.
Does anyone know some design that can help me?
EDIT: the stucture of my classes
the init()
function is really big because shader
and frag
parameters are paths file and I perform some task on them, pass the result of that perform to opengl and returns me a ID
that is the program static variable, all clases with opengl part implement this same process, the parameter camera
is just to attach it into a camera
class Square {
// static variable all classes have
static GLuint program;
// other glparameters not in common, initialized in the same static init() method
static GLint uniform1;
static GLint uniform2;
public;
// the static init function has the same header on all the classes
static init(const char* shader, const char* frag, const char *camera);
}
and maybe some structure I'd want is
class Square {
static GLuint program;
static const char *vertex = "hardcode";
static const char *frag = "hardcode";
static const char *cam = "harcode";
static init();
/// or somethig like
static Initializer init(
"harcode shader", "hardcode frag", "hardcode camera",
[&] (void) ->void {
//this is the init function
}
);
public:
}
This is one more solution how your task can be solved. The idea is to have some initialization list (std::vector) of functions that should be called in yout Opengl_Initializer::init() :
std::vector<std::function<void()>> initializer_list;
If we can put all your Square/Circle/Triangle... init functions into this list, your task become trivial - just iterate list and call all functions:
// inside Opengl_Initializer::init()
for (auto fn : initializer_list)
fn();
You can add functions manually, for example, from int main():
initializer_list.push_back(&Square::init);
...
But I suggest that you need some arhitecture design that will make you able adding functions into initializer list without changing main or any other global code. To solve this task we can make small helper class that will register your init functions automatically:
struct OpenGLHelper_initializer
{
OpenGLHelper_initializer(std::function<void()> fn)
{
initializer_list.push_back(fn);
}
};
So you can declare instance of this class in your Square/Circle:
struct Square
{
static OpenGLHelper_initializer __initializer;
};
And in your Square.cpp file:
OpenGLHelper_initializer Square::__initializer(&Square::init);
So, when program loads, all this initializer will be constructed and all your "init" function will be registered into initializer_list.
This looks like more code, but it will make you able to add as many shapes as you need without changing Opengl_Initializer::init(); or main.cpp or any other global code
Your can now remove init functions, if you dont like them and use lambdas:
// in square.cpp
OpenGLHelper_initializer Square::__initializer([](){
std::cout << "Square is initialized now" << std::endl;
});
Here is complete source code (Updated with using static function) (but without cpp files - all in one):
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
/////////////////////////////////////////
// opengl_helper.h
// this is some manager class that knows what should be initialized later
struct OpenGLHelper
{
typedef std::function<void()> function_type;
static std::vector<function_type>& get_initialization_list();
static void register_initializer(function_type fn);
static void run_init();
};
// helper class that will register some function at construction time
struct OpenGLHelper_initializer
{
OpenGLHelper_initializer(OpenGLHelper::function_type fn)
{
OpenGLHelper::register_initializer(fn);
}
};
/////////////////////////////////////////
//opengl_helper.cpp
// using this function we will make our initializer_list be constructued
// before adding anything into it
std::vector<OpenGLHelper::function_type>& OpenGLHelper::get_initialization_list()
{
static std::vector<function_type> initializer_list;
return initializer_list;
}
// function that puts initializer into a list.
void OpenGLHelper::register_initializer(OpenGLHelper::function_type fn)
{
get_initialization_list().push_back(fn);
}
void OpenGLHelper::run_init()
{
for (auto fn : get_initialization_list())
fn();
}
/////////////////////////////////////////
// figure.h
// here is sample class that will be registered for initialization
struct Square
{
static int to_be_initialized;
// static member that will register Square class to be initialized
static OpenGLHelper_initializer __initializer;
};
/////////////////////////////////////////
// Square.cpp
int Square::to_be_initialized = 0;
// this is the most interesting part - register square into initializer list
OpenGLHelper_initializer Square::__initializer([](){
Square::to_be_initialized = 15;
std::cout << "Called Square::init: " << to_be_initialized << std::endl;
});
int main()
{
std::cout << "Before initialization : " << Square::to_be_initialized << std::endl;
OpenGLHelper::run_init();
std::cout << "After initialization : " << Square::to_be_initialized << std::endl;
return 0;
}
Output:
Before initialization : 0
Called Square::init: 15
After initialization : 15
BTW, such way of initialization is used by QT's metatype system - it uses macros to simplify code
UPDATE: As Ben suggested, we can eliminate small memory leak from bynamic link allocation if we will put initialization list into a static function. Here is new code