tisdag 9 augusti 2011

A Nifty Resource Manager

Here's some meat before we get to the pudding. Every hobby game engine (worth a damn) will needs a resource manager of some sort. This being "next-gen" and all, we got a few requirements on our resource manager as well:

  • It should manage ALL types of assets
  • It should support automatic hot loading of ALL assets
  • It should manage resource dependencies

So without further ado, meet the resource interface (a bit trimmed down) from which all our specific resources will inherit:

class IResource
{
    public:
        IResource( string filename );
        virtual void release() = 0;
        virtual void reload() = 0;
        bool needsReloading();

    protected:
        string    m_filename;
        FILETIME  m_lastModifiedTime;
};

This resource system is based on the assumption that each and every resource is stored using a separate file (something which isn't always the case, but for sake of discussion). The needsReloading() function simply checks the modified file time of the resource and returns true if the file has been modified.

The release() function simply releases all memory etc. tied up by the resource, and the reload() function loads the resource in from the file again. Now we just need a manager class (usually a singleton) to keep track of all the resources:

class ResourceManager
{
    public:
    
        template<class T>
        T* getResource( string strFilename )
        {
            if( m_resources.count( strFilename ) > 0 )
                return dynamic_cast<T*>( m_resources[ strFilename ] );

            // create and add new resource
            T* pResource = new T( strFilename );
            m_resources[ strFilename ] = pResource;
            return pResource;
        }

        void update();
        void releaseAll();

    protected:
        map<string, IResource*>    m_resources;
};

The ResourceManager class keeps a map of string (filenames) and resources (specific resources of various types). Every time a resource is requested it checks the map and see if it has already been created (if not it creates it with some template magic and adds it to the map). Note that in a proper engine you'd probably use a hash table and instead of strings you'd use hashed string IDs instead. But for your average hobby project with not too many thousands of assets this should work just fine.

To get a resource you simply call:


IResource* pSomeResource = ResourceManager::getInstance()->
                           getResource<MyResourceType>( "Resources\\MyResource.bin" );

In the update function of the ResourceManager we check whether any assets have been updated and if so, we call the reload function:

void ResourceManager::update()
{
    // loop over all the assets
    for( map<string, IResource*>::iterator it=m_resources.begin(); 
         it != m_resources.end(); ++it )
    {
        // check if assets needs to be reloaded
        if( (*it).second->needsReloading() )
        {
            // reload resource
            (*it).second->reload();
        }
    }
}

Note that this should of course be spread out over time, it's quite unnecessary to check this every single frame. That's more or less all there's to it. Managing dependencies between different assets is also something that should be handled by the resource manager. For example a mesh might add dependencies to stuff like materials (which might govern the vertex format of the mesh). Should the material then be updated, the resource manager will also call the reload() function of all the meshes that are dependent on that material and so forth.

Another thing to note is that the whole automatic hot loading, dependency registration etc. are things that shouldn't be in the final build of course. So the easiest thing to do is to wrap all that logic in a '#ifndef FINAL' preprocessor block.

A bit more fleshed out version is available here: ResourceSystem.zip
(Build & Start the exe, then change the values in the resource text files and watch the magic happen)

torsdag 28 juli 2011

Development Cycle

Back in the time when I was young... I would start a game project, dive into it head first without thinking, planning or even designing. After a few weeks I would have gotten lots done, a game almost, but the code would look like most people's attic or basement do. This is about the time when the code would become cumbersome to maintain. It would also be around this time when I would be distracted by something shiny and rush off to start the next epic project. A quick glance at my old project folder shows I got over 70 of these unfinished projects. Each and every one of these project would reuse exactly 0 lines of code between them (with the exception of the odd copy/pasted/modified line).

Then I reached puberty... This was around the time I got my first job in the industry. I got to see how the real developers did it. It seemed my betters were building game projects in layers were the low level layers could be reused between game projects. Not being a complete idiot I quickly picked up this idea and started building my own framework of reusable code... (On the other hand scratch that... Since I hadn't figured this out after 70 or so unfinished hobby projects, perhaps I was a complete idiot). Anyways, the only thing that changed was that I was spending my hobby time writing game engines instead of game projects. Instead of 70 unfinished games I now soon have around 10 unfinished game engines.

When I grow old... I think I will complete the cycle and go back to just simply writing games from scratch. I think I will know enough to select projects of a manageable size. I think I will have no other ambition with the project other than to have fun making it... and I think I will never grow old.

Hello world!

So I've been hearing about this new cool thing called blogging... apparently it's the latest thing so I thought I would give it a go.

My plan is to put stuff I do, learn and figure out while programming games here. But like with all my little pet projects we'll see how long I manage to stay focused on one thing.