• Advertisement
Sign in to follow this  

Graphics engine structure + resource manager questions

This topic is 4342 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

Ok, finally I have started to make a plan on what to do to get my engine up and running. Before, I was making components and not dealing with the bigger issue. So now I have some questions with the bigger issue. I am using direct x, if that matters. 1) The resource manager holds all resources, textures, ect so they are not loaded twice. Should the resource manager handle any loading, with some exceptions? I am in the middle of moving my terrain engine into a lib, and obviously the raw height data file does not have to be handled with the manager, but should the manager take care of all vertex and index buffer creation and destruction? In that case, what should the resource manager handle? I would assume so, but would like a consensus to see what other people do. I have not dealt really with meshes, so I don’t know how the meshes will fit in here but I am assuming that they will. 2) After putting my thoughts on paper, the graphics engine is made out of a few components, the resource manager, terrain, sky rendering, meshes, particle systems, and water. I cannot think of anymore. There will be a scene manager, which will take care of partitioning, and instancing out game objects (going for the component scene management). Now, the scene manager will take care of the rendering messages, but where should I actually render? The simple case would be a renderer class, but will it have to compute data from the scene manager and the resource manager to put the object together, or is this overly complicated? As I said, I have not dealt with animated meshes so I don’t know if they will have an adverse effect on my plan. 3) What other graphics engine components should there be? (sound, scripting, input, physics and scene management will not be tied to the graphics engine, however the scene management will require some of the components, such as the resource manager.) 4) Does my plan seem good? Or is it overly complicated and I don’t know what I am talking about or doing? Also: would the best method to check and see if a resource is loaded be to keep a matching array that stores the filename? then if a request for a texture is send, it will search the texture storage array, if it is founf, give the address to the matching element in the texture array, otherwise, load a new one and add the texture and filename to the respective arrays? Or would it be in an array of structs, which hold filename, and the texture data in that? Or I am assuming there is a more conventional way? [Edited by - Valor Knight on March 29, 2006 11:11:38 PM]

Share this post


Link to post
Share on other sites
Advertisement
We need to step back and think in more abstract terms. Stop and think what a resource manager is should be in charge of. "Managing resources," you say. How so? perhaps:

- retrieves resources when requested
- makes sure you don't load the same things twice
- loads resources

Notice we are talking about "resources". Not meshes, sound fx, graphics, or any other thing. This is all rather abstract at this point. Ideally, you want to encapsulate as much of the specifics as possible. For instance, if you want to add sound to your engine, instead of kludging together another part of the resource manager and building a monolithic mess, make your actual resource manager very abstract. Put all the loading/dumping code for specific resources into separate classes. That way you can add new resource types easily (or you can change what libraries you use for those resources without recompiling the actual manager)

So the manager, theoretically, should just be able to say:

ResourceManger::LoadResource( name ) {
appropriate_module.LoadThing( name );
}

All the resource-specific code could go in "appropriate_module".

NOTE: these are just polite and helpfull suggestions. There are plenty of ways to deal with this. YMMV, and all that.

For my manager, i keep names of all my resources and do bookkeeping. I force clients to check in and out resources using their own name. Like this:

Mgr->GetGraphic( "graphic_name", "my_name");

Now, the manager knows two things: 1) that the resource has been checked out exactly once, and 2) that the resource has been checked out by a specific client.

If i run the program, i can at any time get a diagnostic report from the manager that simply lists who has what checked out and how many times.

If all clients check resources in, the resource is dumped and memory freed. Yeah!

Share this post


Link to post
Share on other sites
Wow, thanks for the great reply.

Yea, after I started looking at Ogre's resource manager, I figured it must have to be abstract. But this brings up new questions.

I think I am starting to usderstand the more I looked at the code, and read your post. Say I want a Texture resource manager, I would derive it from the resource manager class. The resource magaer class would contain load, delete, ect virtual functions, to be dealt with if needed in the derived classes. These other managers would contain thier own code to deal with meshes, textures, sounds ect. They would then load them into thier own vectors or arrays (I have seen std::map in ogre's manager but have never seen it before - what does it do?).

Then would you need a resource manager - manager? If I only wanted one class where I could go Mngr->Load(TEXTURE, "filename");(TEXTURE is enumed) Then would this class contain instances or pointers to the other managers?

Still have the question for finding the resource in the managers, should the name be just the filename and path? I see no other way for class 1 creating a texture and then class 4 needing/wanting to load the same texture (without knowing about class 1)

in yours, Mgr->GetGraphic( "graphic_name", "my_name"); what are the names signifying?

Hopefully I am starting to get it [wink]

Share this post


Link to post
Share on other sites

I have a separate module for D3D things and logically it has it's own resource management which is exposed to the engine. Although, I never found too much neede to unify that particular interface.

On the engine side, I have a tree structure which contains description of practically everything used in the program, for example, the about models and their animations but also about the program structure, scene entities such as vehicles, characters.
With the information stored in the tree I am able to create that particular object, when it is needed - and release when not needed - and recreate ... etc. Of course this tree doesn't contain information about the textures since they are managed by the graphics API.

Share this post


Link to post
Share on other sites
Just going to throw my own experience with my engine here.

The way I did a resource manager, I abstracted the concept in this phrase: "a module respnsible for loading data from the drive and processing it, so that it fits the engine's internal data structure for that data type.".

Data types can be shaders scripts, lua scripts, mesh data, sound data, texture data, etc...
Quote:
File --> Resource Loader --> Data Filter(s) --> Memory Structure
The data is read by the apropriate Resource Loader for that file format, then it might be post-load processed by a Data Filter (i have a DF for Meshes, that calculates normal data if it isn't present).

How does the engine know which Resource Loader to call? Simple, by looking at the file extension of the resource you're trying to load.

The engine has an internal Registry, and you can register a loader simply:
Quote:
Register( type, extension, function_ptr );
Register( "Res_Load", "3ds", res_load_3ds );
The above code registers a certain function as a resource loader for a certain file extension. When the function gets called, it receives two parameters:
- A pointer to a file class, so that the function can read the file
- A pointer to a data structure, that the function is responsible for correctly filling up

Using this method, my plugin system allows plugins to register their own resource importers/exporters and data filters.

To export a resource that is already in mmory in the engine, all I need to do is call a registered "Res_Save" function, and pass to it the file class pointer and a data structure pointer.

Using this simple scheme, I've loaded ASE files into the engine, calculated the mesh's normals, and other atributes, TriStripify the mesh data, and then export using my own XM0 file format.

A resource loading function returns true or false if the data was successfully loaded onto the engine. In case it returns true, another module is responsible for adding the file and its now-in-memory data to a list of "already loaded resources".

Before calling a Resource Loader funtion, it checks if that resource has already been loaded, very simple design.

Hope it helped. [wink]

Share this post


Link to post
Share on other sites
Hmm, I didn't mention about the resource loading thing.

I explained a bit about my descriptor system but the benefit of the system is that it doesn't require any extra loader system (although I have that kind of "register-loader" system for loading certain things, but they aren't related).

The idea is that when a resource data is needed, it is asked from the corresponding descriptor. If the (resource) data is already loaded then a pointer to it is returned, otherwise the class described by the descriptor is created and initialised by the descriptor.

So for example, when a data of a model descriptor is requested and the data hasn't been loaded yet, the program creates a new model object (through a class factory) and then passes a pointer of the descriptor to the "Create" function. The model object has now a chance to load any data it might need. So there is no need for a separate loader in this case, the class knows itself how to set things up.

So might argue about the unsafety of the pointer conversion, but a similar method is used also in the famous 3d modelling software.

Share this post


Link to post
Share on other sites
I think I am starting to understand. I have translated what I think has been said/and tried to pseudo code it.

class IResourceManager
{
private:

protected:
/* Resource array or something - what should it be (vector, list, map or what)? will it have to be a template to allow generic-ness? */

public:
IResourceManager(void);
virtual ~IResourceManager(void);

virtual void create(); // this will be used by all other derived classes to load and take care of it thier own way
//will add the resource to the vector, array, map or whatever

virtual void unload( ulong handle );
virtual void unload( const std::wstring &name );
virtual void unloadall();

virtual void reloadall(); //Could be useful with lost devices

virtual void remove( ulong handle );
virtual void remove( const std::wstring &name );
virtual void removeall();
};

class TextureResource : public IResourceManager
{
private:

public:
bool create(); //passes inputs to loadTexture, adds to list if created succesfully
bool loadtexture(/*params to load a texture file, load the texture and if successful, returns true and create will add it to the resource list*/);
// other functions as needed
};

class Resources
{
private:
std::vector<IResourceManager *> _ResourceManagers;
//I guess this would have to be a map or hash map to add in the Id ("Texture") to be searched/refrenced easily.
public:
bool Register(/* ... */);
bool Load();//calls create() for appropriate class
bool Request();
};



So now, to use the data:
	
say Mngr is an instance of Resources.
Mngr->Register("Texture", TextureResource(passing in new()-ed) );
// adds a TextureResource class into the resource types - ID = Texture
Mngr->AddFileType("Texture", ".dds");
// going on the topic of being allowed to either declare it is a texture object, or it will look for the extension


in some game class:
*texture1 = Mngr->Load("Texture", "filename.dds"); //loads into the "Texture" resource manager
*texture2 = Mngr->Load("filename2.dds");//it is regestered so .dds is sent to the "Texture" manager
//If it already exists, return the pointer to the data, otherwise, it will create it and return the pointer

Am I getting on track??

Still have questions about how to hold the data.
1) will I need template or something to have the actual data stay in the derived class? how can I have generic containers to put lets say IDirect3DTexture9 in one and ID3DXMesh in another?
2)what should organize the data? std::map or std::hash_map? or both. I an guessing the name of the resource will be it's filename, thus it would be an easy search
3) creating a new type of resource manager, would there be a better way (such as passing in only the name) of creating a new instance of a resource manager over passing the refrence in?

Many thanks on the replies

[Edited by - Valor Knight on March 30, 2006 5:33:23 PM]

Share this post


Link to post
Share on other sites
Here are a few more things to consider. Again, i'm not recommending one over the other. Just more approaches you can consider.

1) use a universal interface. You could go with operations like this:

Resource* GetResource(RESOURCE_TYPE, "name");

The gotcha here is that you get a generic Resource* in return. You would have to cast that. That's dumb. It's a nice interface though!

Workaround:

Templates. Yes, that's where it's really at! Templates are almost totally overlooked by even experienced programmers it seems. I'm just warming up to them myself. Here, for instance, you could have a template member function that looks like this:

TYPE* GetResource<TYPE>("name");

Then, though some kind of magic, you could select the right resource from the right list of resources.

2) Monolithic approach. Have one resource manager class and have a lot of functions:

Graphic* GetGraphic("name");
Sound* GetSound("name");
Font* GetFont("name");
Mesh* GetMesh("name");

PRO: it's all in one place. Oh, so simple.
CON: you have to recompile the manager everytime you futs with the resource types. BUT, usually you know what types you need at the beginning of the project. They are pretty obvious. It's not really the kind of thing you update all the time.

This is actually the approach i've taken. It's not as flexible, but like i said, you shouldn't have to flex it very often.

3) Separate managers. You already touched on this. Personally, i'm not too keen on it, although it does make things nicely modular. I like one-stop-shopping resource managers though ;-)

-----------------

Other things to try:

- you asked how you actually would store the resources internally. Most usually use a map, like so:

map< string, Resource* >;

I personally have a different map for each resource type. SoundMap, TextureMap, FontMap, etc...

- XML! I actually name and configure all my resources externally using XML (through TinyXML lib). With this, you can tell your system ahead of time what you want loaded (or at least make loadable), what the file names are, and what the aliases are. For instance, i can have an entry like this:

<TEXTURE name="Smoke Puff" file="foo/xyz.png">
<ALIAS name="enemy dies" />
<ALIAS name="gun fires" />
<ALIAS name="brick falls" />
</TEXTURE>

Now the resource manager loads this and links the 3 aliases with this filename. When any of the aliases are requested, it loads the file and returns the texture. Note here that the same texture is used for 3 different things! You can do this with sound effects and fonts and all the other resources as well.

- Hide implimentation details. You are best advised to create your own classes for resources. For instance, if you want sound fx, create your own SoundEffect class instead of just using your library's native structure (like SDL_MixChunk* or whatever). Hide all the library specific business underneath your resource and management classes.

The reason this is important is because you can completely withstand any changes you make if you change libraries. For instance, if you switched from SDL to FMOD for sound, you would have to change your loading and dumping code only. All the rest of your code that actually uses your homebrewed SoundEffect class would be totally untouched by such a huge change!

Share this post


Link to post
Share on other sites
As a disclaimer, I've skipped everything everyone else has written in this thread.

When I was doing this, there were a couple goals I had in mind:
  • Black box. The people using a resource are not necessarily entitled to know what that resource's interface is. The only knowledge they've been granted is that it exists under a certain class name.
  • Reference counts are necessary, so that the system can know what objects are in use.
  • Time stamps are necessary for streaming purposes. What this means in a practical sense is that the system needs to trap every time a resource is used.
  • While string identifiers are useful, string lookups should be made rare.
  • Access needed to be indirect, again due to streaming concerns.
  • All of the resource types are known at compile time, so there is no need for dynamic/runtime type voodoo.
These concerns led me to finally build a handle based system. Each handle is a black box wrapper that internally contains an integer index into the internal array of resources. The rendering core object provides a number of managers. Clients request these managers to get some resource handle by string, and a handle is returned immediately (the actual resource is scheduled for loading in the background if necessary, and does not stall the function). Then all of the rendering functions and structures take handles (which are intended to be value types, they're passed by value in most cases). The managers internally allow the handles to be resolved to actual pointers, but external clients cannot retrieve handles. Resolving a handle to a pointer is a straightforward array access and is basically free. The manager keeps a map/hashtable of string->array index which are used to look up string names and build handles when requested.

I think that covers the main points of my design.

Share this post


Link to post
Share on other sites
Just a slight caveat before I begin, Resource Managers are one of those things that you'll design differently as you gain experience. Maybe don't mind so much if yours isn't totally swanky to start out with. It'll get better. The important thing is that it works, so you can get on with coding the game [and learning how your resource manager rocks/sucks]...


Ahem. That said, my current resource manager incarnation is a little different than most here. The key is resource definitions. A resource definition [in my setup] is simply a string/string pair. The key is the resource name, used like most here, and is pretty much the only thing available to the common user. The value is instructions about how to load the resource.

One of the major downsides to [most] of the methods listed above is it's near impossible to change loaders. If resources are moved into say a .pak file, or your sounds are now streamed... it's a big mess. With the resource definition method, only the value [the loading instructions] needs to be changed, and only in one config file.

I use a templated base resource manager to do that interpretation, and common tasks. Individual managers (sound,texture,font...) inherit from the base manager, and specify the constructed return type [returning raw resources is bad mmmkay

(Why?

Because you can't inherit from raw resources. If you return say... an image rather than a texture, you can later return varieties of things that inherit from an image.

Because you generally can't do proper reference counting semantics with a raw resource.

Because you shouldn't trust the programmer to do [or remember to do] the right things with the resource you return.

)].

The common base allows for common elements to be shared, but still allow for more specific specialization for resources that don't quite fit. It also allows for API specific implimentations to be done seperate from the rest, or even from their base manager.

Share this post


Link to post
Share on other sites
Quote:
Original post by Promit
These concerns led me to finally build a handle based system. Each handle is a black box wrapper that internally contains an integer index into the internal array of resources. The rendering core object provides a number of managers. Clients request these managers to get some resource handle by string, and a handle is returned immediately (the actual resource is scheduled for loading in the background if necessary, and does not stall the function). Then all of the rendering functions and structures take handles (which are intended to be value types, they're passed by value in most cases). The managers internally allow the handles to be resolved to actual pointers, but external clients cannot retrieve handles. Resolving a handle to a pointer is a straightforward array access and is basically free. The manager keeps a map/hashtable of string->array index which are used to look up string names and build handles when requested.

I like it, I wanted to do streaming later on, and doing it this way to start would be all the better. A couple of things though, say you wanted a to load a texture image, you would call the manager to make an image, and the return a unique handle to that image. Now, if another resource wants to load the same texture, it looks up the texture name string (its filename, right?) if it exists, return the handle (which is an int or long), if not create one? Now say I wanted to use the texture, how do you get it out seeing you only have a handle to the resource? would the resource manager include functioniality to render/manipulate as well?



Quote:
Original post by leiavoia
1) use a universal interface. You could go with operations like this:

TYPE* GetResource<TYPE>("name");

Then, though some kind of magic, you could select the right resource from the right list of resources.

Yea, that is what I think will have to work

Quote:
Original post by leiavoia
- you asked how you actually would store the resources internally. Most usually use a map, like so:
map< string, Resource* >;

What is the diffrence between a has_map and a map? I have seen in them both being used in a resource manager at the same time


Quote:
Original post by Telastyn
Just a slight caveat before I begin, Resource Managers are one of those things that you'll design differently as you gain experience. Maybe don't mind so much if yours isn't totally swanky to start out with. It'll get better. The important thing is that it works, so you can get on with coding the game [and learning how your resource manager rocks/sucks]...

That is like my whole project so far, I dare not enter the gui, or the particle system code anymore, I will just delete it and start over

Share this post


Link to post
Share on other sites
Quote:
Original post by Valor Knight
Quote:
Original post by Promit
These concerns led me to finally build a handle based system. Each handle is a black box wrapper that internally contains an integer index into the internal array of resources. The rendering core object provides a number of managers. Clients request these managers to get some resource handle by string, and a handle is returned immediately (the actual resource is scheduled for loading in the background if necessary, and does not stall the function). Then all of the rendering functions and structures take handles (which are intended to be value types, they're passed by value in most cases). The managers internally allow the handles to be resolved to actual pointers, but external clients cannot retrieve handles. Resolving a handle to a pointer is a straightforward array access and is basically free. The manager keeps a map/hashtable of string->array index which are used to look up string names and build handles when requested.

I like it, I wanted to do streaming later on, and doing it this way to start would be all the better. A couple of things though, say you wanted a to load a texture image, you would call the manager to make an image, and the return a unique handle to that image. Now, if another resource wants to load the same texture, it looks up the texture name string (its filename, right?) if it exists, return the handle (which is an int or long), if not create one? Now say I wanted to use the texture, how do you get it out seeing you only have a handle to the resource? would the resource manager include functioniality to render/manipulate as well?
It first checks a string lookup, and if it finds it a new handle is returned and the resource ref count is incremented (handles are value types remember). As for using the texture, there's a very clear division between internal renderer and external clients, enforced by a DLL boundary. You can only tell the renderer your intentions. Roughly speaking, you will tell it to queue a rendering command of the form (heavily simplified):
struct RenderCommand
{
Handle<Model> Model;
Matrix Transform;
Handle<Texture> Texture;
};
So you package and send one of those structs off to the renderer interface, and it knows how to get a Model* and a Texture* and use the relevant objects correctly. You are never granted an actual pointer, and for that matter you don't even know what the objects look like. The external header only forward declares them, which allows you to build templates of a certain form but doesn't actually grant you any knowledge about them. (Technically you're not even entitled to know if the resource is in memory or not, but I do allow you to query.)

Share this post


Link to post
Share on other sites
ok, then the renderer should be able to get more than the handle out of the resource manager? such as a pointer to the texture, if the texture is available?
And I assume you have a resource manager for each type of resource, texture, model, ect.. derived from a base resource manager, and then a manager that manages what resource types get loaded into what - so you dont need to know all the resource manager avail?

Share this post


Link to post
Share on other sites
Quote:
Now say I wanted to use the texture, how do you get it out seeing you only have a handle to the resource? would the resource manager include functioniality to render/manipulate as well?


Your resource manager just manages resources. The resources themselves ought to know how to do their job. Example: My 2D engine needs OpenGL Textures to work. OpenGL references it's textures via a simple integer. That's fairly benign (you can't accidently delete an int), however the drawing code to actually draw an image on the screen is the same regardless of what image i'm drawing. So the resource manager hands out a special homebrewed "Texture" class instead of OpenGL integers and drawing them by hand. This gives me an interface like this:

Texture::Blit(params);

The clients that need to draw a texture are completely isolated from the underlying drawing code. In fact, the client would have no idea even what library was being used. It could be OpenGL, SDL, DirectDraw, or anything else.

Because the drawing code and the clients that draw are separated by encapsulating drawing in a class ("Texture"), you can change the implementation of how you draw with no changes to client code. This is ideally how you should treat all of your resources. Don't hand out raw pointers or anything that could directly manipulate the system. Just hand out little stubs that perform functions. The stubs know how to do their job. It's not the client's business.

Texture::Blit()
Sound::Play()
Model::Render()
Font::DrawText("hello world")
. . . etc . . .

Share this post


Link to post
Share on other sites
well, yea it will have to be in another class. I was just commenting on his method where it only gives out a handle to the resource. How does one access the data if I only have a handle, I would have to get a pointer to the data or use the data somehow.

in renderer
DrawTexture( resourcemanager.getTexture("handle") ); ???
then you would need to perhaps make the renderer a freind class so that the data can be hidden for the user, but still able to be extracted for the rendering process?

Share this post


Link to post
Share on other sites
Yeah, the prefered option would be something like this:

Texture* t = Manager->GetTexture("laser");

t.Blit(x,y); // draws image.

So the manager might give out a pointer to something, but since it's encapsulated by your own Texture class, it's not something you can directly manipulate.

This is opposed to something less secure like handing out raw pointers:

SDL_Surface* surf1 = Manager->GetTexture("laser");

// rogue code!
delete surf1;

// (Manager still thinks the pointer it gave out is still good, so it gives it out again if asked) :

// ask for the same texture
SDL_Surface* surf2 = Manager->GetTexture("laser");

// do something with it:
SomeFunction( surf2 );

// *** segfaults ***

Share this post


Link to post
Share on other sites
I do something a little like what Prozak and Telastyn in that I use a resource definition, except it's a little different. (Going to try and space it somewhat to make reading easier)

I like mine because it took way too long to program, and I'm somewhat proud of it. The main downfall that comes with it is the fact that it isn't to secure in the fact that hve things register in the source files themselves (a.k.a, they are registered in a global initialization). Is that bad practice? Yeah, I think so, but I don't want to have to go to a new source file to register everything every time I add something new to be registered. All in all, it would probably be best to register them all in a function, but I'm kind-of lazy right now...

To start with, I have two base classes: 'RDEF_BASE' and 'CResource'. CResource is used for the actual resources themselves, like the sprites, fonts, sounds, etc., and RDEF_BASE is for the loading format, and contains data such as the resource's name, a pointer to the resource that it is connected (will be explained later).

With the resourece base (CResource), I have a virtual Load() and Unload() method. CResrouce::Load(...) takes one argument, a pointer to the resource-definition base (RDEF_BASE*), and CResource::Unload() has no arguments, since it, well, unloads. The resource also has a virtual type function, that returns, well, its type (to be compared with the base).

In the resource definition base (RDEF_BASE, r.def. base for short), it has information such as the file name where the resource is stored (or, if its a virtual file, the virtual file's name), and it also has a pointer to the resource that is registered to it (ex. 'resource_register("sndKaboom",&sndKaboom)'). With that pointer, it can control when the resource itself loads, unloads, or even reloads. It is also very handy when you plan on loading only certain parts of your resources. For that reason, I have 'load points' that can be defined in each r.def. base. Whenever you're loading a certain level with certain graphics and such, you would simply have to define the load point with a name in the resource definition file (later explained), and in the code somewhere, you would load/unload those points (ex. 'resource_load_point("jungle")' and later 'resource_unload_point("jungle")'). There is also a default load point, which would be 'resource_[load/unload]_point(-1)'.

I could go into greater detail, but I bet I have already exceeded what I should have typed.
But to finally tie it all together, I have my resource definition type (not base), called 'RDEF_TYPE'. This has a function pointer to create a child of RDEF_BASE, and it has a name, such as "SPRITE" or "LEVEL", which corresponds with the definitions in the file.
I will go ahead and stop here because I can't think of a way to explain this.

If anyone would like the source to what I am blabbering about, merely ask.
[Soon, soon I will release my game engine...].

EDIT: Come to think about, I just remembered that most of my stuff is all global, and maybe I ought to put it in a manager class...

Share this post


Link to post
Share on other sites
With my system, it's critically important to understand that the outside clients who are given handles are never handed a real class instance. A Handle<T> has a very limited set of interfacing options that are available to everybody. It can be compared to other handles for the same resource type, it can report whether it is a valid handle (anybody is allowed to construct an invalid one) and it can be "touched", which updates the timestamp (same idea as the UNIX touch command). The manager allows you to request a new handle, to get the string name associated with a handle, and it can tell you if the related object is currently resident in memory. So the game code does something like:
Entity ent = new Entity();
ent.Model = Renderer.Models.GetModel( "/%current_map/models/chair.spark" );
ent.Transform = Matrix.Identity;
ent.Texture = Renderer.Textures.GetModel( "/%current_map/textures/chair.dds" );
...
//this function does NOT exist, but it gets the point across
Renderer.RenderEntity( ent );

At no point in this code can an actual Model or Texture ever be retrieved. There are simply no functions in the handle or any of the managers that allow you to do it. In the renderer, however...
void Renderer::RenderEntity( const Entity& ent )
{
Model* model = m_Models.GetPointer( ent.Model );
if( model == NULL )
{
m_Models.Precache( ent.Model );
return;
}

Texture* tex = m_Textures.GetPointer( ent.Texture );

//continue with actual rendering
}
So this GetPointer function is available internally to the renderer which is the one giving out the handles in the first place. The code which gets and holds a handle is not given a pointer. Not ever. There is no need. (Note that this is dual implemented in C# and C++, and C# changes some of the details.)

Share this post


Link to post
Share on other sites
So, to re-word what Promit just said (as I can see you getting confused here!):

The thing that dishes out the handles has a mechanism for retrieving pointers to the data (given a handle), internally.

In his case, it's the Renderer. In yours it'll be the ResourceManager, which I presume will have to be the friend of the Renderer if it's to be of any use. You don't want to expose pointers to resources to the whole program, just allow them to pass around handles without worrying about exactly what they mean. Hooray for encapsulation :)

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Here is my resource manager via boost:

#ifndef RESOURCE_MANAGER_H
#define RESOURCE_MANAGER_H
#pragma warning(disable: 4786)
#pragma warning(disable: 64)
#include
#include
#include
#include
#include

template
class Resource_Manager
{

public:

typedef T_ value_type; // std library convention

typedef boost::shared_ptr Resource_Ptr;
typedef boost::weak_ptr Resource_Observer;
typedef std::map Resource_Map;

Resource_Manager() {};
~Resource_Manager() {};

Resource_Observer Request_Resource(const std::string & name)
{
Resource_Map::iterator it = mResources.find(name);

if (it == mResources.end())
{
Resource_Ptr Raw_Resource(new T_);
Raw_Resource->Load(name);
mResources.insert(std::make_pair(name, Raw_Resource));
Resource_Observer Resource(Raw_Resource);
return Resource;
}
else
{
return Resource_Observer(it->second);
}
}

void Request_Resource_Removal(const std::string & name)
{
Resource_Map::iterator it = mResources.find(name);

if (it != mResources.end())
{
mResources.erase(it);
}
}

private:
Resource_Map mResources;
};

#endif

That is probably the most basic of a templated resource manager example I can give, loads objects (resources) that have load functions, returns an observer pointer, pretty simple. Won't repeat resources.

Share this post


Link to post
Share on other sites
Thanks for the info, after promit posted about his method, that got me thinking that that would be best for me since I will need streaming later on. As it turns out there was a game programming gem about it here So that has gotten me started. I like the fact that the client knows nothing of the engine data so my resource manager will probably be friends with the scene manager and the renderer to allow for the extraction of the data without exposing it.

EDIT: actually one last quick question, do you have a single class to manage the resource managers, or do you refrence them individually?

[Edited by - Valor Knight on April 3, 2006 9:58:34 PM]

Share this post


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

  • Advertisement