Progress update! (very excited about it)A long time ago I've written serialization system which was used for my Qt animation editor. But now I've expanded it immensely and remade most of it in ImGui! (still hard to believe I did it in just one day)
Here's how serialization code looks:
void Animation::registerClass(MetaBuilder<Animation>& builder)
{
builder.add("name", &Animation::name);
builder.add("looped", &Animation::looped);
builder.add("frameCount", &Animation::frameCount);
builder.add("frameRect", &Animation::frameRect);
builder.add("frameTime", &Animation::frameTime);
builder.add("offset", &Animation::offset);
builder.add("offsets", &Animation::offsets);
builder.add("frames", &Animation::frameRects);
builder.add("sounds", &Animation::soundInfo);
}
The ImGui window is composed by using info from
Meta<T> class and each type has specialized element for displaying and editing it! (Bools have checkboxes,
sf::Time has
InputInt with
ms label etc.)
But that's not all. I've previously had some problems with circular dependencies which prevented me from making recursive serialization, but now I've solved it! I can also serialize some STL containers (
vector, map, unordered_map) and some SFML stuff (
Vector2<T>, Time, Rect<T>)
Here's what I can do. Suppose I have a classes A and B.
struct A {
std::unordered_map<std::string,B> bs;
}
struct B {
std::string name;
int age;
}
Here's how A registered:
builder.add("bs", &A::bs);
And here's how B registered:
builder.add("name", &B::name);
builder.add("age", &B::age);
Suppose there's an instance of A like this:
A a;
a.bs = {
"first_key" = B{"John Smith", 28},
"second_key" = B{"Jane Doe", 34}
};
And now I can serialize any instance of A to json by just doing this:
This will return this JSON:
{
"first_key" = {
name = "John Smith",
age = 28
},
"second_key" = {
name = "Jane Doe",
age = 34
}
}
Here are two things to note:
unordered_map is serialized into a JSON map. Each value of the map is serialized by using
Meta<B>::serialize (that's where recursion comes in!)
For defined types (int, float, bool, string, etc.) there are
Meta<> specializations, so recursion stops there.
Same stuff works for ImGui almost the same, but the neat thing is that I can map each member directly to a GUI control by passing a pointer to the member into ImGui function. There's no copies, no temporary objects.
The C++ object is modified directly. And this is really great and awesome!
And here are some questions I have...1) How should I handle error handling? Should I throw exceptions? I want to be able to write error messages like this: "Error: Animation::name should be string, but int was passed" if JSON is incorrect. Should serialize/deserialize throw exceptions like this? (Right now I only return true if deserialization was successful and false otherwise... which is not great, of course!), or maybe there are other ways to handle errors... (Silently ignoring them is not the way!)
2) Is there any reliable way to create function for template class which will be called on template class instantiation? Is such thing possible? How can I achieve it and be sure that static members are initialized at the point the function is called?
For example, I write this function:
void Animation::registerClass(MetaBuilder<Animation>& builder)
and I want it to be called automatically by Meta<Animation> class. I want this to be called automatically because of Meta<T> instantiation:
Meta<T>::init() {
T::registerClass(MetaBuilder<T>());
}
P.S. All meta stuff code will be open sourced soon! I'll also show how to use ImGui with it a bit later.