Extending the resource management system to incorporate a new resource type can be tricky, but with a little guidance, it is fairly straight forward.
For this tutorial we will be using a simple class called Object
class Object { public: Object(); Object(int x, int y); int x; int y; };
First you will need to add a constructor that will load from the resource management system and an instance of CL_Resource to store our resource information in.
class Object { public: Object(); Object(int x, int y); Object(const std::string &resource_id, CL_ResourceManager *manager); int x; int y; private: CL_Resource resource; };
Now, before we actually define our new constructor for Object, lets create our new
class CL_ResourceData_Object : public CL_ResourceData { public: ResourceData_Object(CL_Resource &resource); virtual ~ResourceData_Object(); Object &get_object(); private: void on_load(); void on_unload(); Object object; };
The constructor tells the resource to attach the data through this instance of CL_ResourceData. Later when you ask your resource manager to load the object it will call the on_load() function which actually reads in your data. Notice that the call to get_attribute takes two parameters in this instance. The first is obviously the variable name, but the second is the default value which is used when the attribute is not found.
ResourceData_Object::ResourceData_Object(CL_Resource &resource) : CL_ResourceData(resource) { resource.attach_data("object", this); } ResourceData_Object::on_load() { CL_Resource resource = get_resource(); int x = atoi( (resource.get_element().get_attribute("x","50")).c_str() ); int y = atoi( (resource.get_element().get_attribute("y","75")).c_str() ); object.x = x; object.y = y; } ResourceData_Object::on_unload() { object = Object(); }
In order for this to work, we have to create a custom callback function to load your new resource types. The callback function just looks to see if the new resource is of our custom type, and in that event creates a new instance of our resourcedata type.
static void resource_added(CL_Resource &resource) { std::string type = resource.get_type(); if (type == "object") new ResourceData_Object(resource); }
And then in your initialization routines just add a line like:
CL_Slot slot_resource_added - CL_ResourceManager::sig_resource_added().connect(&resource_added);
Now just add that constructor for Object that we nearly forgot about. This function will just ask the our CL_ResourceManager for the instance of our object, then we tell it load it up. Then just get our our data from the resource, but if it returns no data then the name you specified is not of type Object. Then just get out your data however you like, a copy constuctor or overloaded = operator comes in real handy here.
Object::Object(const std::string &resource_id, CL_ResourceManager *manager) { resource = manager->get_resource(resource_id); resource.load(); ResourceData_Object *data = (ResourceData_Object *) resource.get_data("object"); if(!data) throw CL_Error("Resource '" + resource_id + "' is not of type 'object'"); x = data->get_object().x; y = data->get_object().y; resource.unload(); }
The last thing to do is to call your resource. For a resource file looking like:
<resources> <object name="object01" x="20" y="20" /> </resources>
Just create your object like this:
Object *my_object = new Object("object01", new CL_ResourceManager("my_resourcefile.xml"));Thats it!