Jump to content
  • Advertisement
Sign in to follow this  
dmatter

loading resources - inheritance or functions

This topic is 4914 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

While designing my engine all my resources (and by resources I mean meshes, textures, sounds etc) all support a single file format to be loaded from. This was so I could get an engine up and running in the first place. Now I've come to the decision that I shall implement more file formats for my meshes and textures etc. After thinking about it I am still at an indecision as how to implement it. Currently I have a single mesh class and a single texture class both with a Load(std::string filename); This is called by the SceneManager's LoadMesh function called whenever the program requests a mesh. If the user calls Load directly (ie without the SceneManager involved) then I've hacked together a way to notify the SceneManager of this (because it stores all the meshes etc by filename) I don't like that however because it poses excess responsibility on the Mesh class to notify the SceneManager AND the load function must check that it wasn't previously loaded. None of this would be a problem if the user simply didn't have access to this Load function in the first place. Now to support more formats, I could add more functions to the mesh class such as LoadMD2, LoadOBJ etc and in the interest of extensibility the user could create a CustomMesh class with load functions for other types such eg Load3DS. The SceneManager would check the file extension and call the required function on the mesh. This again poses all the problem associated with calling Load on the mesh directly, as described above. Alternatively I could create a base class IMesh and have inherit from that each type of mesh eg class MD2Mesh : public IMesh This also makes it easy to extend new types into the engine. I might then need a pure virtual Load(...) = 0; function (except this exposes the load interface to the user who again shouldn't be able to call Load on the resource directly) then every specialisation of the IMesh class overrides this Load function. The SceneManager's job would then be to determine the file extension, instantiate the correct concrete mesh type, call Load and return the mesh as an *IMesh. I don't really like the idea the user can call Load on a resource directly because it adds extra responsibility onto the function. Making it private would obviusly solve the problem but then the SceneManager would have to be a friend (don't like that either). How is resource loading achieved in most other engines? I do like the idea of having an IMesh base class with MD2Mesh, 3DSMesh etc. Perhaps certain optimisations can also be achieved through StaticMesh and DynamicMesh and have MD2Mesh inherit from DyanmicMesh. Many Thanks David

Share this post


Link to post
Share on other sites
Advertisement
That's basically it. You

- either create an interface with the properties you set as a requirement for your engine to support any given file format and then implement that for any format (a good idea for meshes, since one might have keyframe animations, the other might have bone-based animations)

- or, if you will require data to be in a specific format in the end anyway, create a generalized class for that resource and different loader classes which load and convert the different format into the generalized class (appropriate for image files for example; you probably want tga, jpg, png all to become an array of RGB values in the end).


In one of my projects, I successfully did it like this (simplified, just to give you the idea):

struct Image {
virtual size_t getWidth() = 0;
virtual size_t getHeight() = 0;
};
struct ImageCodec {
virtual bool canLoad(istream &file) { return false; }
virtual auto_ptr<Image> load(istream &file) = 0;
};
struct ImageServer {
void registerCodec(auto_ptr<ImageCdec> NewCodec) {
m_Codecs.insert(NewCodec);
}
auto_ptr<Image> loadImage(istream &file) {
for_each(Codec in m_Codecs) {
if(Codec->canLoad(file))
return Codec->load(file);
}
throw "unsupported image file format";
}
};



-Markus-

Share this post


Link to post
Share on other sites
After looking at some open source engines: Ogre and Irrilcht. These both do it different ways, Ogre has one generalised mesh class (similar to my idea where I have LoadXYZ functions that load the data into the internal format) where-as Irrilcht uses the multiple base classes approach. I like this method better, somehow though Irrilcht does it without the use of the virtual Load function. This therefore prevents the user calling Load on the resource itself.

@Cygon: Thats a good for for when one needs to load into one internal format, as you say just RGBs, doesn't matter where they come from the're all stored the same way. But for a mesh I could have many different versions of a mesh, I could optimize non-moving objects in a StaticMesh and have animated meshes inherit from DynamicMesh. I really like that approach.

So now I have more-or-less decided (unless someone can give reasons against) to use the inheritance approach rather than the many-methods aproach.

Thinking ahead, now it might be nice to be able to supply additional parameters for the loading function per mesh-type (quick example: A custom mesh type might support loading different LODs directly from the file, an additional parameter might be required such as a 'bool loadLODs' or 'char numLODsToLoad'). My point being that a virtual Load(std::string fileName) forces all to use that 1 parameter.

My other problem still arises if the user calls Load directly on the mesh, since it would need to ensure it has not been loaded before (not so bad) and have to notify the SceneManager that it has been loaded and therefore changed its filename (very bad).
This would require that it knows which scenemanager it was registered to (there can be more than one scenemanger - no singletons in my engine) and it requires the SceneManager to have a public function to allow the mesh to notify it.
Hence that causes yet another dilemna of what happens if the user decides to call the scenegraph's public 'notify' function -> a potential memory leak, depending on whatever (and whats probably a legal/valid) thing they want to do with the mesh afterward.

So my two main aims are:
* how to prevent the user from calling Load directly on the mesh instead of through the SceneManager.
* How to make Load more flexible for derived types so they aren't bound to the parameters specified by a virtual Load method in the base class (and the base Load method would have to be public which contradicts the above bullet-point)

Any more thoughts.
Thanks so far

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!